继承方式和访问限定符都有三种,public、protected以及private,其中public和private在之前就介绍过,如果是protected那么只有子类能访问,外界无法访问。子类继承方式表示继承的类是什么属性,子类继承方式不写默认为私有。
父类private成员在子类中无论以什么方式继承都是不可见的,其含义是私有成员还是被继承到子类中,但是在语法上了派生类对象不管在类里面还是类外面都无法访问。
继承方式大多以public为主,并且不提倡使用protected和private继承,因为继承下来的成员都只能在子类的类里面使用,实际中维护性不强。
公有继承被看做相近类型,可以进行隐式类型转换。
隐式类型转换会生成临时变量,但是在公有继承下,父类与子类是is-a(你就是我)的关系,子类对象赋值给父类对象/父类指针/父类引用,我们认为是天然的,中间不产生临时对象,称为父子类赋值兼容规则(也叫切割/切片)。
当父类和子类都有同一个成员时,会优先使用自己的成员,如果我们要使用父类成员可以加上父类的域。由此得知,继承中同名函数会构成隐藏,不管参数和返回值,所以尽量不要使用同名函数。
我们以下面代码为例:
class Person { public: Person(const char* name, int age) :_name(name) ,_age(age) { cout << "Person构造函数" << endl; } Person(const Person& p) :_name(p._name) ,_age(p._age) { cout << "Person拷贝构造" << endl; } Person& operator=(const Person& p) { cout << "Person赋值重载" << endl; if (&p != this) { _name = p._name; _age = p._age; } return *this; } void Print() { cout << _age << " " << _name << endl; } ~Person() { cout << "Person析构函数" << endl; } protected: int _age = 18; string _name = "Mick"; }; class Teacher : public Person { public: void Print() { cout << Person::_age << endl; } protected: int _age = 10; int _jobid = 0; };
子类不写默认构造函数,那么会去调用父类的默认构造函数。
如果要显示初始化子类,且要用父类成员时,需要把父类当成完整对象,复用父类成员完成初始化。
拷贝构造需要在子类中取到父类成员,我们对子类切片即可。
同理,赋值重载也是这种方法。
子类析构要特殊一点,因为多态的存在,析构函数名会被统一处理成destructor,所以父子类析构函数会构成隐藏,当我们调用父类析构时需要加上域。并且,构造时是先构造父类再构造子类,析构则是先子后父,原因在于父类先析构了,但子类依然能够访问父类,那么就会存在风险,所以要先释放子类,父类访问不了子类,则不存在该风险,编译器为了确保安全,所以只需要析构子类,父类会自动帮我们析构。
完整代码如下,可以自己调试学习:
#include<iostream> using namespace std; class Person { public: Person(const char* name, int age) :_name(name) ,_age(age) { cout << "Person构造函数" << endl; } Person(const Person& p) :_name(p._name) ,_age(p._age) { cout << "Person拷贝构造" << endl; } Person& operator=(const Person& p) { cout << "Person赋值重载" << endl; if (&p != this) { _name = p._name; _age = p._age; } return *this; } void Print() { cout << _age << " " << _name << endl; } ~Person() { cout << "Person析构函数" << endl; } protected: int _age = 18; string _name = "Mick"; }; class Teacher : public Person { public: Teacher(const char* name,int age,int id) :Person(name,age) ,_age(age) ,_jobid(id) { cout << name << " " << _age << " " << _jobid << endl; } Teacher(const Teacher& t) :Person(t) //切片 ,_age(t._age) ,_jobid(t._jobid) { cout << "Teacher拷贝构造" << endl; } Teacher& operator=(const Teacher& s) { if (&s != this) { Person::operator=(s); //这里要指定,不然会发生隐藏 _jobid = s._jobid; _age = s._age; } return *this; } //由于多态原因,析构函数统一会被处理成destructor //父子类的析构函数构成隐藏 //为了保证析构安全,先子后父 //父类析构函数不需要显示调用,子类析构函数会自动调用父类 ~Teacher() { // Person::~Person(); cout << "Teacher析构" << endl; } void Print() { cout << _name << " " << _age << " " << _jobid << endl; } private: protected: int _age = 10; int _jobid = 0; }; int main() { Teacher t("张三",18,20023030); Teacher t1("李四", 10, 20043030); t = t1; t.Print(); return 0; }
在C++11之前,我们想要一个类不能被继承,可以将构造函数私有化,而在C++11后,我们可以在父类加上final来禁止继承。
静态成员继承的是使用权,它存在静态区中,属于整个类。
多继承格式如下:
class student { //成员 }; class Teacher { //成员 }; //多继承格式 class Assistant : public student, public Teacher { //子类成员 }
但是在C++中可能会出现菱形继承,assistant会拥有两份person成员。
菱形继承不仅会造成代码冗余,并且会出现二义性,编译器无法识别我们想调用哪个类的成员,必须要加上类域才能使用。
解决方法是在冗余的继承类加上virtual(虚继承)
class A { public: int _a; }; class B : public A { public: int _b; }; class C : public A { public: int _c; }; class D : public B, public C { public: int _d; }; int main() { D d; d.B::_a = 1; d.C::_a = 2; d._b = 3; d._c = 4; d._d = 5; return 0; }
我们在内存窗口中看一下对象d的存储情况,发现了数据冗余,A出现了两次。
如下代码,B类和D类大小一样,但一个是继承一个是组合,区别在于继承权限更大,组合只能使用公有的成员,且在类外不能直接调用成员函数,从可维护性来看,组合更好,因为组合依赖关系不强,耦合度低,有助于保持每个类被封装,但从便利角度来看,继承更好用。
#include<iostream> using namespace std; class A { public: void func() { } protected: int _a; }; class B : public A { public: void f() { func(); //直接调用 _a = 1; //可以访问_ } protected: int _b; }; class C { public: void func() { } protected: int _c; }; class D { public: void f() { _cc.func(); //间接调用 _c = 1; //不可以访问 } protected: int _d; C _cc; }; int main() { B bb; D dd; bb.func(); //可以调用 dd.func(); //无法调用 return 0; }
题目一:
题目二:
答案:D的构造函数会先走初始化列表,而继承顺序决定声明顺序,并且这里是虚继承(如果没有虚继承A会调用两次,A自己本身不需要走初始化列表),A只调用一次,所以选A
以上便是继承的全部内容,如果有疑问或者建议都可以私信笔者交流,大家互相学习,互相进步!🌹
因篇幅问题不能全部显示,请点此查看更多更全内容
Copyright © 2019- huatuo9.cn 版权所有 赣ICP备2023008801号-1
违法及侵权请联系:TEL:199 1889 7713 E-MAIL:2724546146@qq.com
本站由北京市万商天勤律师事务所王兴未律师提供法律服务