wordpress 投票网站,wordpress mip 主题,WordPress+dos漏洞,网站seo 最好友元 关键字#xff1a;friend
友元的三种实现
全局函数做友元类做友元成员函数做友元
全局函数做友元
//建筑物类
class Building
{//goodGay全局函数是Building好朋友#xff0c;可以访问Building中私有成员friend void goodGay(Building building);
public:Build…友元 关键字friend
友元的三种实现
全局函数做友元类做友元成员函数做友元
全局函数做友元
//建筑物类
class Building
{//goodGay全局函数是Building好朋友可以访问Building中私有成员friend void goodGay(Building building);
public:Building(){m_SittingRoom 客厅;m_bedRoom 卧室;}string m_SittingRoom;
private:string m_bedRoom;
};
//全局函数
void goodGay(Building building)
{cout 好基友全局函数正在访问 building.m_SittingRoom endl;cout 好基友全局函数正在访问 building.m_bedRoom endl;}
void test01()
{Building building;goodGay(building);
}
类做友元
class Building;
class goodGay;
class goodGay
{
public:goodGay();void visit();
private:Building* building;
};
//建筑物类
class Building
{ friend class goodGay;
public:Building();string m_SittingRoom;
private:string m_bedRoom;
};
Building::Building()
{this-m_SittingRoom 客厅;this-m_bedRoom 卧室;
}
goodGay::goodGay()
{building new Building;
}
void goodGay::visit()
{cout 好基友全局函数正在访问 building-m_SittingRoom endl;cout 好基友全局函数正在访问 building-m_bedRoom endl;
}void test01()
{goodGay gg;gg.visit();
}
成员函数做友元
class Building;
class goodGay;
class goodGay
{
public:goodGay();void visit();void visit2();//只让visit访问私有属性visit2不能访问
private:Building* building;
};
//建筑物类
class Building
{ friend void goodGay::visit();
public:Building();string m_SittingRoom;
private:string m_bedRoom;
};
Building::Building()
{this-m_SittingRoom 客厅;this-m_bedRoom 卧室;
}
goodGay::goodGay()
{building new Building;
}
void goodGay::visit()
{cout 好基友全局函数正在访问 building-m_SittingRoom endl;cout 好基友全局函数正在访问 building-m_bedRoom endl;
}
void goodGay::visit2()
{cout 好基友全局函数正在访问 building-m_SittingRoom endl;//cout 好基友全局函数正在访问 building-m_bedRoom endl;
}void test01()
{goodGay gg;gg.visit();}
重载
运算符重载
加号运算符重载 成员函数重载
class Person
{
public://1. 成员函数重载号Person operator(Person p){Person temp;temp.m_A this-m_A p.m_A;temp.m_B this-m_B p.m_B;return temp;}int m_A;int m_B;
};
void test01()
{Person p1;p1.m_A 10;p1.m_B 10;Person p2;p2.m_A 10;p2.m_B 10;//成员函数重载本质调用//Person p3 p1.operator(p2);Person p3 p1 p2;cout m_A: p3.m_A , m_B: p3.m_B endl;}
全局函数重载和函数重载
class Person
{
public:int m_A;int m_B;
};
//2. 全局函数重载号
Person operator(Person p1, Person p2)
{Person temp;temp.m_A p1.m_A p2.m_A;temp.m_B p1.m_B p2.m_B;return temp;
}
//函数重载的版本
Person operator(Person p1, int num)
{Person temp;temp.m_A p1.m_A num;temp.m_B p1.m_B num;return temp;}
void test01()
{Person p1;p1.m_A 10;p1.m_B 10;Person p2;p2.m_A 10;p2.m_B 10;//全局函数重载本质调用//Person p3 operator(p1, p2);Person p3 p1 p2;//运算符重载 也可以发生函数重载Person p4 p1 100;cout m_A: p3.m_A , m_B: p3.m_B endl;cout m_A: p4.m_A , m_B: p4.m_B endl;}
总结1对于内置的数据类型的表达式的运算符是不可能改变的
总结2不要滥用运算符重载
左移运算符重载
只能利用全局函数重载左移运算符因为如果利用成员函数重载左移运算符 p.operator(cout) 简化版本为pcout无法实现cout在左侧
重载运算符目的只输出对象p就可以实现输出p中的所有成员属性。
class Person
{friend ostream operator(ostream cout, Person p);
public:Person(int a, int b){m_A a;m_B b;}
private:int m_A;int m_B;
};
// 只能利用全局函数重载左移运算符
ostream operator(ostream cout, Person p)//本质operstor(cout, p)
{cout m_A p.m_A , m_B p.m_B;return cout;
}void test01()
{Person p(10, 10);cout p endl;
}
递增运算符重载
class MyInteger
{friend ostream operator(ostream cout, MyInteger myint);
public://重载前置运算符返回引用为了一直对一个数据进行递增操作MyInteger operator(){//先进行运算m_Num;//再将自身做返回return *this;}//重载后置运算符//void operator(int) //int代表占位参数可以用于区分前置和后置递增MyInteger operator(int){//先 记录当时结果MyInteger temp *this;//后 递增m_Num;//最后将记录结果做返回return temp;}MyInteger(int num){m_Num num;}
private:int m_Num;
};ostream operator(ostream cout, MyInteger myint)
{cout myint.m_Num endl;return cout;
}void test01()
{MyInteger myint(0);cout (myint);cout myint;cout myint;cout myint;
}
总结前置递增返回引用后置递增返回值。
赋值运算符重载
class Person
{
public:Person(int age);~Person();Person operator(Person p);int* m_Age;
};
Person::Person(int age)
{//将年龄数据开辟到堆区m_Age new int(age);
}
Person::~Person()
{if (m_Age ! NULL){delete m_Age;m_Age NULL;}
}
//重载 赋值运算符
Person Person::operator(Person p)
{//编译器是提供浅拷贝//m_Age p.m_Age;//应该先判断是否有属性在堆区如果有先释放干净然后再深拷贝if (m_Age ! NULL){delete m_Age;m_Age NULL;}//深拷贝m_Age new int(*p.m_Age);//返回对象本身return *this;
}
void test01()
{Person p1(18);Person p2(20);Person p3(25);p1 p2 p3;cout p1年龄 *p1.m_Age endl;cout p2年龄 *p2.m_Age endl;cout p3年龄 *p3.m_Age endl;}
关系运算符重载
作用重载关系运算符可以让两个自定义类型对象进行对比操作
class Person
{
public:Person(string name, int age);bool operator(Person p);bool operator!(Person p);private:string m_Name;int m_Age;
};Person::Person(string name, int age)
{m_Name name;m_Age age;
}
bool Person::operator(Person p)
{if (m_Name p.m_Name m_Age p.m_Age){return true;}return false;
}
bool Person::operator!(Person p)
{if (m_Name p.m_Name m_Age p.m_Age){return false;}return true;
}
void test01()
{Person p1(Bob, 18);Person p2(Bob, 20);if (p1 ! p2){cout p1和p2不相等 endl;}else{cout p1和p2相等 endl;}
}
函数调用运算符重载
函数调用运算符()也可以重载由于重载后使用的方式非常像函数的调用因此称为仿函数仿函数没有固定写法非常灵活
重定义可打印函数和可加函数
class MyPrint
{
public:void operator()(string text);
private:};
void MyPrint::operator()(string text)
{cout text endl;
}
class MyAdd
{
public:int operator()(int num1, int num2){int ret num1 num2;return ret;}private:};void test01()
{MyPrint myprint;myprint(hello world!); //由于使用起来非常类似于函数调用因此称为仿函数MyAdd myadd;int ret myadd(10, 20);cout ret ret endl;//匿名对象cout MyAdd()(23, 23) endl;}继承
继承是面向对象三大特性之一
继承的好处减少重复代码
语法 --- class 子类继承方式
子类 也称为 派生类
父类 也称为 基类
class A: public B;
继承方法
公共继承保护继承私有继承 继承中的对象模型
父类中所有非静态成员属性都会被子类继承下去
父类中私有成员属性是被编译器给隐藏了因此是访问不到但确实被继承下去了
使用开发工具查看对象模型
打开工具窗口定位到当前cpp文件的盘符然后输入
cl /d1 reportSingleClassLayout查看的类名 所属文件名 继承中构造和析构顺序
继承中先调用父类构造函数再调用子类构造函数析构顺序与构造相反 子类和父类同名成员处理
子类对象可以直接访问到子类中同名成员
如果通过子类对象 访问到父类中同名成员需要加作用域 如果子类中出现和父类同名的成员函数子类的同名成员会隐藏掉父类中所有同名成员函数
如果想访问到父类中被隐藏的同名成员函数需要加作用域
多继承语法
C允许一个类继承多个类
语法class 类继承方式 父类1继承方式 父类2
class Son: public Base1, public Base2
{}
多继承中如果父类出现了同名情况子类使用时候要加作用域
C实际开发中不建议用多继承
菱形继承
菱形继承概念
两个派生类继承同一个基类
又有某个类同时继承者两个派生类
这种继承被称为菱形继承或钻石继承
典型菱形继承案例 菱形继承问题
菱形继承带来的主要问题是子类继承两份相同的数据导致资源浪费以及毫无意义利用虚继承可以解决菱形继承的问题
继承之前 加上关键字 virtual 变为虚继承
Animal类称为 虚基类 //动物类
class Animal
{
public:int m_Age;
};
//利用虚继承解决菱形继承的问题
//继承之前 加上关键字 virtual 变为虚继承
//Animal类称为虚基类
class Sheep: virtual public Animal{};
class Tuo : virtual public Animal{};
class SheepTuo : public Sheep, public Tuo{};void test01()
{SheepTuo st;st.Sheep::m_Age 18;st.Tuo::m_Age 21;//当菱形继承两个父类拥有相同属性需要加以作用域区分cout st.Sheep::m_Age st.Sheep::m_Age endl;cout st.Tuo::m_Age st.Tuo::m_Age endl;//这份数据我们知道 只要有一份数据就可以菱形继承导致数据有两份资源浪费//加了虚继承可直接输出不需加作用域cout st.m_Age st.m_Age endl;
}
多态
多态的基本概念
多态是C面向对象三大特性之一
多态分为两类
静态多态函数重载和运算符重载属于静态多态复用函数名动态多态派生类和虚函数实现运行时多态
静态多态和动态多态区别
静态多态的函数地址早绑定 - 编译阶段确定函数地址动态多态的函数地址晚绑定 - 运行阶段确定函数地址
动态多态满足条件
有继承关系子类重写父类的虚函数
动态多态的使用
父类的指针或引用指向子类对象
class Animal
{
public://虚函数virtual void speak(){cout 动物在说话! endl;}
};//猫类
class Cat : public Animal
{
public://重写 函数返回值类型 函数名 参数列表 完全相同void speak(){cout 小猫在说话! endl;}
};
class Dog : public Animal
{
public:void speak(){cout 小狗在说话! endl;}
};
//执行说话的函数 虽然传入Cat但是还是动物说话因为地址早绑定在编译阶段确定函数地址
//如果想执行让猫说话那么这个函数地址就不能提前绑定需要在运行阶段绑定地址晚绑定
//解决方法virtual 虚函数
void doSpeak(Animal animal)
{animal.speak();
}void test01()
{Cat cat;doSpeak(cat);Dog dog;doSpeak(dog);
}
多态原理 多态案例 - 计算机类
案例描述分别利用普通写法和多态技术设计实现两个操作数进行运算的计算机类
多态的优点
代码组织结构清晰可读性强利于前期和后期的扩展以及维护
传统写法
//传统计算器写法
class Calculator
{
public:int getResult(string oper){if (oper ){return num1 num2;}else if (oper -){return num1 - num2;}else if (oper *){return num1 * num2;}//如果要提供新的运算需要修改源码}int num1;int num2;
};
void test01()
{Calculator c;c.num1 10;c.num2 10;cout c.num1 c.num2 c.getResult() endl;cout c.num1 - c.num2 c.getResult(-) endl;cout c.num1 * c.num2 c.getResult(*) endl;
}
多态写法
//利用多态写计算器
//多态好处
//1. 组织结构清晰
//2. 可读性强
//3. 对于前期和后期扩展以及维护性高//实现计算器抽象类
class AbstractCalculator
{
public:virtual int getResult(){return 0;}int num1;int num2;
};
//加法计算器类
class AddCalculator: public AbstractCalculator
{
public:int getResult(){return num1 num2;}
};
//乘法计算器类
class MulCalculator : public AbstractCalculator
{
public:int getResult(){return num1 * num2;}
};
//减法计算器类
class SubCalculator : public AbstractCalculator
{
public:int getResult(){return num1 - num2;}
};void test02()
{//多态使用条件//父类指针或引用指向子类对象AbstractCalculator* c new AddCalculator;c-num1 10;c-num2 10;cout c-num1 c-num2 c-getResult() endl;delete c;SubCalculator a;AbstractCalculator m a;m.num1 20;m.num2 20;cout m.num1 - m.num2 m.getResult() endl;
}
纯虚函数和抽象类
在多态中通常父类中虚函数的实现是毫无意义的主要都是调用子类重写的内容
因此可以将虚函数改为纯虚函数
纯虚函数语法virtual 返回值类型 函数名参数列表0
当类中有了纯虚函数这个类也称为抽象类
抽象类特点
无法实例化对象子类必须重写抽象类中的纯虚函数否则也属于抽象类
//纯虚函数
//只要有一个纯虚函数这个类称为抽象类
class Base
{
public:virtual void func() 0;
};
class Son: public Base
{
public:void func(){}
};void test01()
{//抽象类无法实例化对象//Base b; //new Base;//Son s; //子类必须重写父类中的纯虚函数否则无法实例化对象Base* base new Son;base-func();
}
多态案例2 - 制作饮品
案例描述
制作饮品大致流程为煮水 - 冲泡 - 倒入杯中 - 加入辅料
利用多态技术实现本案例提供抽象制作饮品基类提供子类制作咖啡和茶叶 class AbstractDrink
{
public://煮水virtual void boil() 0;//冲泡virtual void brew() 0;//倒入杯中virtual void pour() 0;//加入辅料virtual void addSomething() 0;//制作饮品void makeDrink(){boil();brew();pour();addSomething();}
};
//制作咖啡
class Coffee : public AbstractDrink
{
public:void boil(){cout 煮矿泉水 endl;}void brew(){cout 冲泡咖啡 endl;}void pour(){cout 倒入咖啡杯中 endl;}void addSomething(){cout 加糖和牛奶 endl;}
};
//制作茶叶
class Tea : public AbstractDrink
{
public:void boil(){cout 煮水 endl;}void brew(){cout 冲泡茶叶 endl;}void pour(){cout 倒入茶杯中 endl;}void addSomething(){cout 加柠檬 endl;}
};
//制作函数
void doWork(AbstractDrink* abs)
{abs-makeDrink();delete abs;
}
void test01()
{//制作咖啡doWork(new Coffee);cout ----------------------------------------- endl;//制作茶叶doWork(new Tea);
}
虚析构和纯虚析构
多态使用时如果子类中有属性开辟到堆区那么父类指针在释放时无法调用到子类的析构代码
解决方式将父类中的析构函数改为虚析构或纯虚析构
虚析构和纯虚析构共性
可以解决父类指针释放子类对象都需要有具体的函数实现
虚析构和纯虚析构区别
如果是纯虚析构该类属于抽象类无法实例化对象
虚析构语法
virtual ~类名(){}
纯虚析构语法
virtual ~类名()0;
class Animal
{
public:virtual void speak() 0;Animal(){cout animal构造函数调用 endl;}~Animal(){cout animal析构函数调用 endl;}
};
class Cat : public Animal
{
public:Cat(string name){m_name new string(name);cout cat构造函数调用 endl;}~Cat(){if (m_name ! NULL){cout Cat析构函数调用 endl;delete m_name;m_name NULL;} }void speak(){cout *m_name 小猫在说话 endl;}string* m_name;
};
void test01()
{Animal* cat new Cat(Tom);cat-speak();//父类指针在析构的时候不会调用子类中析构函数//导致子类如果有堆区属性出现内存泄漏delete cat;
}
上面代码无法调用cat的析构函数 将父类的析构函数变为虚函数即可访问子类析构函数。
class Animal
{
public://纯虚函数virtual void speak() 0;Animal(){cout animal构造函数调用 endl;}//利用虚析构可以解决 父类指针释放子类对象时不干净的问题/*virtual ~Animal(){cout animal析构函数调用 endl;}*///纯虚析构virtual ~Animal();};
Animal::~Animal()
{cout animal纯析构函数调用 endl;
}
class Cat : public Animal
{
public:Cat(string name){m_name new string(name);cout cat构造函数调用 endl;}~Cat(){if (m_name ! NULL){cout Cat析构函数调用 endl;delete m_name;m_name NULL;}}void speak(){cout *m_name 小猫在说话 endl;}string* m_name;
};
void test01()
{Animal* cat new Cat(Tom);cat-speak();delete cat;}
总结
虚析构或纯虚析构就是用来解决通过父类指针释放子类对象如果子类中没有堆区数据可以不写为虚析构或纯虚析构拥有纯虚析构函数的类也属于抽象类
多态案例3 - 电脑组装 private:CPU* m_cpu;VideoCard* m_videoCard;Memory* m_memory;
};
class IntelCpu : public CPU
{
public:void calculate(){cout Intel的CPU正在计算。。。。。。 endl;}
};
class IntelVc : public VideoCard
{
public:void display(){cout Intel显卡正在显示。。。。。。 endl;}
};
class IntelMem : public Memory
{
public:void storage(){cout Intel的内存条正在存储。。。。。。 endl;}
};class LenovoCpu : public CPU
{
public:void calculate(){cout Lenovo的CPU正在计算。。。。。。 endl;}
};
class LenovoVc : public VideoCard
{
public:void display(){cout Lenovo显卡正在显示。。。。。。 endl;}
};
class LenovoMem : public Memory
{
public:void storage(){cout Lenovo的内存条正在存储。。。。。。 endl;}
};void test01()
{Computer* computer1 new Computer(new IntelCpu, new IntelVc, new IntelMem);Computer* computer2 new Computer(new LenovoCpu, new LenovoVc, new LenovoMem);Computer* computer3 new Computer(new IntelCpu, new IntelVc, new LenovoMem);computer1-doWork();cout ------------------------------------- endl;computer2-doWork();cout ------------------------------------- endl;computer3-doWork();delete computer1;delete computer2;delete computer3;
}