01、继承:
#include <iostream> using namespace std; /* 回顾上节的内容: const 重载 运算符重载 -> () 函数对象 今天的内容 继承 比如: 人 -->身高 年龄 ...吃饭 睡觉 打豆豆 --> 成员函数 成员变量 小学生 吃饭 睡觉 打豆豆 写作业 上学 身高 年龄 学号 大学 吃饭 睡觉 大打豆豆 谈恋爱 写论文 玩游戏 学习 身高 年龄 绩点 几个类 -->相似的属性 行为 继承 某个类 继承一个类(基类/父类)中所有的成员(成员变量/函数)加上自己的属性/行为成为一个新的类(派生类/子类) 继承: 1.吸收父类成员(除去构造和析构) 子类会吸收父类的所有成员 2.调整父类的成员 2.1访问控制 2.1.1 继承方式 public private protected 2.1.2 父类的成员 public private protected 访问权限 private < protected < public 父类的 private 成员 子类中不能访问 其余的成员 就按照继承方式中最安全的一种 作为子类的属性 继承方式 默认私有 2.2 隐藏 子类中定义一个父类相同的成员变量或者成员函数 //父类中的成员函数或者变量就会被隐藏 通过子类对象访问 访问到的是新的函数/变量 //隐藏的是父类继承过来的函数和成员(子类中生效) //如果说子类中的函数和父类继承的函数 函数名相同 参数不一样 继承的函数和新写的函数构造重载 //子类不影响父类 3.添加新成员 子类中添加新成员变量/函数 实现新功能 基类 构造 析构 -->没办法继承 子类要写自己的构造和析构 子类的构造: 1.它必须调用父类的构造函数 (如果没有显示调用 那么就隐性调用了默认的构造函数) 2.需要显示调用 必须使用初始化形参列表 3.先调用父类构造 然后在调用子类构造 4.调用顺序和形参列表中的顺序无关 子类的析构: 1.析构会调用父类的析构 先调用子类析构 然后调用父类析构 2.可以默认调用 不需要显示调用 父类的函数 可以访问父类的成员 修改 访问父类中的私有成员 --> 父类公有函数访问 多继承: 一个类继承多个父类 //开发效率 -->提高的开发效率 */ //=======================================类函数==================================== class father { private: int weight; // 体重 float height; // 身高 public: int wealth; father(){ cout << "father的构造" << endl; } father(int x, float y, int z) :weight(x), height(y), wealth(z) { } ~father(){ cout << "father的析构" << endl; } void play(){ cout << "father的play" << endl; } void eat(){ cout << "father的eat" << endl; } }; class son:public father // 后面是继承父类: // 1.父类不是只有一个子类; // 2.子类可能不止有一个父类 // 如果是继承多个父类 逗号隔开 { public: int age; // 年龄 float height; // 身高 int wealth; son():father() // 调用了父类的构造函数 { cout << "调用了子类的构造函数" << endl; // weight; 父类的私有成员 子类中不能访问 //eat(); // 调用父类中eat() } /** 父类的成员 -->父类的构造函数 初始化 子类 初始化子类的成员 子类 继承了父类的成员 -->继承过来的成员 可以重新赋值 */ son(int x, float y, int z) :age(x), height(y), wealth(z), father(x,y,z) // 有参构造 { } void play(){ cout << "son的play" << endl; } }; int main() { father ft; cout << sizeof(ft) << endl; son sn; cout << sizeof(sn) << endl; sn.height; sn.eat(); sn.play(); getchar(); return 0; }
02、多继承:
#include <iostream> using namespace std; /* 多继承 继承两个或者多个基类的所有成员 1.继承 子类会调用父类的构造函数 调用顺序只和继承顺序相关 2.析构 和构造函数顺序相反 3.要访问某个类继承过来的成员 基类名::成员名 访问(注意访问权限) 菱形继承 A派生B和C B和C共同派生D D就有来自A的两份拷贝(一份来自B 一份来自D) 虚继承 主要解决菱形继承 (关键字:virtual) 虚继承不影响B和C 影像的是D 如果B 和C 只有一个加virtual 那么和继承顺序有关 一般的话 不建议使用多继承 */ class fruit // 水果 { public: int color; fruit(){ cout << "水果类的构造函数" << endl; } ~fruit(){ cout << "水果类的构造函数" << endl; } void eat() { cout << "可以生吃" << endl; } }; class vegetable // 蔬菜 { public: int color; vegetable(){ cout << "蔬菜类的构造函数" << endl; } ~vegetable(){ cout << "蔬菜类的构造函数" << endl; } void cook() { cout << "煮熟吃" << endl; } }; class tomato :public fruit, public vegetable // 多继承 用逗号隔开 { // 先构造水果类 然后构造蔬菜类 public: int color; tomato() :vegetable(), fruit() { /** 构造中初始化形参列表顺序 不影响调用顺序 */ } void see() { vegetable::color = 2; // 从类vegetable中继承的color fruit::color = 5; color = 6; cout << vegetable::color << fruit::color << color << endl; } }; //================================================例子============================================= class A { public: int x; }; class B :virtual public A { }; class C :virtual public A { }; /* 车 四个轮子 -->B四个轮子 C四个轮子 -->D 8个轮子 */ class D :public B, public C { public: void print() { B::x = 3; // 虚继承 在最终的孙子类中 只留一个祖父类的拷贝 C::x = 4; cout << B::x << C::x << x << endl; } }; int main() { D d; d.print(); { tomato ta; ta.cook(); // 煮熟吃 ta.eat(); // 生吃 ta.see(); } getchar(); return 0; } /* 作业: 人类 身高 体重 吃饭睡觉 男人类 运动 学生类 学习 考试 -->派生出 男学生类 打印出吃饭睡觉 // 预防菱形继承 */