赋值兼容性原则:子类就是特殊的父类
①子类对象可以当作父类对象使用,②子类对象可以直接赋值给父类对象,③子类对象可以直接初始化父类对象,④父类指针可以直接指向子类对象,⑤父类引用可以直接引用子类对象。
#include <iostream> using namespace std; class Parent { protected: char* name; public: Parent() { name = "Parent"; } void print() { cout<<"Name:"<<name<<endl; } }; class Child:public Parent { protected: int i; public: Child(int i) { this->name = "Child"; this->i = i; } }; int main() { Child child(100); Parent parent = child;//子类对象可以直接赋值给父类对象 Parent* pp = &child; //父类指针可以直接指向子类对象 Parent& rp = child; //父类引用可以直接引用子类对象 parent.print(); pp->print(); rp.print(); return 0; }
输出结果:
继承对象模型:
类在C++编译器的内部可以理解为结构体,子类是由父类成员叠加子类新成员得到的。
问题来了,如何初始化父类成员?父类和子类的构造函数有什么关系?
在子类对象构造的时候需要调用父类构造函数,对其继承来的成员进行初始化。
在子类对象析构的时候需要调用父类析构函数对其继承来的成员进行清理
简单的一个例子:
#include <iostream> using namespace std; class Parent { public: Parent() { cout<<"Parent()"<<endl; } ~Parent() { cout<<"~Parent()"<<endl; } }; class Child:public Parent { public: Child() { cout<<"child()"<<endl; } ~Child() { cout<<"~child()"<<endl; } }; void run() { Child child; } int main() { run(); return 0; }
输出结果为:
①子类对象在创建的时候首先自动调用父类的构造函数,父类构造函数执行结束后,执行子类的构造函数,
②当父类的构造函数有参数时,需要在子类的初始化列表中显示调用。
将上个例子修改一下:
#include <iostream> using namespace std; class Parent { public: Parent(const char* s) { cout<<"Parent()"<<endl; cout<<s<<endl; } ~Parent() { cout<<"~Parent()"<<endl; } }; class Child:public Parent { public: Child():Parent("Parameter from Child!") { cout<<"Child()"<<endl; } ~Child() { cout<<"~Child()"<<endl; } }; void run() { Child child; } int main() { run(); return 0; }
输出结果为:
如果一个类继承自并且有其它的对象作为成员,那么构造函数如何调用?口诀:先父母,后客人,再自己。
#include <iostream> using namespace std; class Object { public: Object(const char* s) { cout<<"Object()"<<" "<<s<<endl; } ~Object() { cout<<"~Object()"<<endl; } }; class Parent : public Object { public: Parent(const char* s):Object(s) { cout<<"Parent()"<<endl; cout<<s<<endl; } ~Parent() { cout<<"~Parent()"<<endl; } }; class Child:public Parent { protected: Object o1; Object o2; public: Child():o2("o2"),o1("o1"),Parent("Parameter from Child!") { cout<<"Child()"<<endl; } ~Child() { cout<<"~Child()"<<endl; } }; void run() { Child child; } int main() { run(); return 0; }
输出:
同名成员变量:当子类中定义的成员变量与父类中的成员变量同名时会发生什么?
子类依然从父类继承同名成员,只是通过作用域分别符::进行同名成员区分,对于机器来说它们只是存储在不同位置的变量,对于人来说看起来是同名的。