面向对象——继承
友元类增加访问权限
不管是按哪一种方式派生,基类的私有成员在派生类中都是不可使用的,如果在一个派生类中要访问基类中的私有成员,可以将这个派生类声明为基类的友元。
class Base { friend class Derive; ... }; |
class Dervie { ... }; |
Derive 类可以直接使用Base中的私有成员。
#include <iostream> using namespace std; class M { friend class N; private: int i, j; void show(void) { cout << "i = " << i << '\t' << "j = " << j << '\t'; } public: M(int a = 0, int b = 0) { i = a; j = b; } }; class N : M { public: N(int a = 0, int b = 0) : M(a, b) {} void print() { show(); cout << "i + j = " << i + j << endl; } }; int main() { N n1(10, 20); M m1(100, 200); n1.print(); return 0; }
同名覆盖原则
- 若未强行指明,则通过派生类对象或类内使用的是派生类中的同名成员
- 如果通过派生类对象访问基类中被覆盖的同名成员,应使用基类名限定
#include <iostream> using namespace std; class Human { private: int age; public: void setAge(int a) { age = a; } int getAge() { return age; } void showAge() { cout << "the human age is " << getAge() << endl; } }; class student : public Human { public: void showAge() { cout << "the student age is " << getAge() << endl; } }; int main() { student jessic; jessic.setAge(12); jessic.showAge(); jessic.Human::showAge(); Human *hp; hp = &jessic; // 为什么输出的是Human的年龄? // 自动类型转换 hp->showAge(); return 0; }
派生类的构造函数和析构函数
// 派生类的构造函数和析构函数 // 构造函数和析构函数是不能够被继承的 #include <iostream> using namespace std; class Human { public: Human() { cout << "a person is constructed!!!!\n"; } ~Human() { cout << "a person is deconstructed!!!!\n"; } }; class Student : public Human { public: Student() { cout << "a student is constructed!!!!\n"; } ~Student() { cout << "a student is deconstructed!!!!\n"; } }; void main() { Student jessic; cout << "this is main function\n"; }
派生类对象的生成过程:先构造基类,在构造派生类;析构的时候,与之相反。
总结:
- 基类的构造函数不被继承,派生类中需要声明自己的构造函数
- 声明构造函数时,只需要对本类中新增成员进行初始化,对继承来的基类成员的初始化,自动调用基类构造函数完成
- 派生类的构造函数需要给基类的构造函数传递参数,如果不传的话编译不会通过
基类构造函数传参
#include <iostream> using namespace std; class Human { private: int age; public: Human(int n) { this->age = n; cout << "a person is constructed!!!!\n"; } ~Human() { cout << "a person is deconstructed!!!!\n"; } }; class Student : public Human { private: int sno; public: Student(int no, int n) : Human(n) { this->sno = no; cout << "a student is constructed!!!!\n"; } ~Student() { cout << "a student is deconstructed!!!!\n"; } }; int main() { Student jessic(10000, 24); cout << "this is main function\n"; return 0; }
注意与组合类中初始化成员对象相区别。
组合类的构造函数的先后顺序
// 添加Pad类 // 组合类对象的构造过程:先基类,后整体;先部分,后整体;(先别人,后自己) #include <iostream> using namespace std; class Pad { public: Pad() { cout << "A Pad is constructed!!!\n"; } ~Pad() { cout << "A Pad is deconstructed!!!\n"; } }; class Human { private: int age; public: Human(int n) { this->age = n; cout << "a person is constructed!!!!\n"; } ~Human() { cout << "a person is deconstructed!!!!\n"; } }; class Student : public Human { private: int sno; Pad pd; public: Student(int no, int n) : Human(n) { this->sno = no; cout << "a student is constructed!!!!\n"; } ~Student() { cout << "a student is deconstructed!!!!\n"; } }; int main() { Student jessic(10000, 24); cout << "this is main function\n"; return 0; }
构造函数的顺序为:
- 基类先执行构造函数
- 然后成员对象执行构造函数
- 最后是派生类执行构造函数
派生组合类初始化
#include <iostream> using namespace std; class Pad { private: int color; public: Pad(int c) { this->color = c; cout << "A Pad is constructed!!!\n"; } ~Pad() { cout << "A Pad is deconstructed!!!\n"; } }; class Human { private: int age; public: Human(int n) { this->age = n; cout << "a person is constructed!!!!\n"; } ~Human() { cout << "a person is deconstructed!!!!\n"; } }; class Student : public Human { private: int sno; Pad pd; public: Student(int no, int n, int c) : Human(n), pd(c) { // 注意:这里是使用对象的实例进行传参 this->sno = no; cout << "a student is constructed!!!!\n"; } ~Student() { cout << "a student is deconstructed!!!!\n"; } }; int main() { Student jessic(10000, 24, 1); cout << "this is main function\n"; return 0; }
多继承&&虚拟继承
主要解决菱形继承问题
穿透继承,对于祖先类中的成员只实例化一次
// 多继承 #include <iostream> using namespace std; class Human { protected: int id; public: void setId(int i) { this->id = i; } }; class Student : virtual public Human { public: Student() { id = 0; } void study() { cout << "Studying ...\n"; } }; class Teacher : virtual public Human { public: Teacher() {} void teach() { cout << "Teaching...\n"; } }; class Counsellor : public Student, public Teacher { public: Counsellor() {} void work() { cout << "working...\n"; } }; int main() { Counsellor ss; ss.setId(20); ss.study(); ss.teach(); ss.work(); return 0; }
多继承构造函数调用的先后顺序
#include <iostream> using namespace std; class OBJ1 { public: OBJ1() { cout << "OBJ1\n"; } }; class OBJ2 { public: OBJ2() { cout << "OBJ2\n"; } }; class Base1 { public: Base1() { cout << "Base1\n"; } }; class Base2 { public: Base2() { cout << "Base2\n"; } }; class Base3 { public: Base3() { cout << "Base3\n"; } }; class Base4 { public: Base4() { cout << "Base4\n"; } }; class Derived : public Base1, virtual public Base2, public Base3, virtual public Base4 { public: Derived() : Base4(), Base3(), Base2(), Base1(), obj2(), obj1() { cout << "Derived ok.\n"; } protected: OBJ1 obj1; OBJ2 obj2; }; int main() { Derived aa; cout << "This is ok.\n"; return 0; }
多继承中构造函数调用的先后顺序与继承的中基类书写的先后顺序有关,并且虚继承基类优先调用,之后是普通的基类(构造顺序与书写顺序保持一致),然后是对象成员类调用构造函数(构造顺序与声明顺序保持一致),最后是本类执行构造函数。
基类与派生类的转换
在需要基类对象的地方,就可以用公有派生类对象来代替。(类型兼容规则)
- 派生类对象可以被赋值给基类对象
- 派生类的对象可以初始化基类的引用
- 指向基类对象的指针也可以指向派生类对象
#include <iostream> #include <string> using namespace std; class Student { public: Student(int n, string nam, float s) { num = n; name = nam; score = s; } void display() { cout << "num:" << num << "\nname:" << name << endl; } protected: int num; float score; string name; }; class Graduate : public Student { public: Graduate(int n, string nam, float s, float w) : Student(n, nam, s), wage(w) {} void display() { Student::display(); cout << "wage: " << wage << endl; } private: int wage; }; int main() { Student studl(1001, "Li", 87.5); Graduate gradl(2001, "Wang", 98.5, 1000); Student *pt = &studl; pt->display(); pt = &gradl; pt->display(); return 0; }
永远渴望,大智若愚(stay hungry, stay foolish)