赞
踩
继承概念:
继承机制是新的类从已有类那里得到已有的特性。亦或从已有类产生新类的过程就是类的派生。原有的类称为基类或父类,产生的新类称为派生类或子类。它是使代码可以复用的最重要的手段。
继承关系和访问限定符:
<单继承>
一个类只有一个直接父类时,称这个继承关系为单继承
- #include<iostream>
-
- class Base
- {
- public:
- Base(int pub = 0, int pro = 1, int pri = 2)
- :_pub(pub),
- _pro(pro),
- _pri(pri)
- {
- cout << "B()" << endl;
- }
- ~Base()
- {
- cout << "~B()" << endl;
- }
- void ShowBase()
- {
- cout << "_pri = " << _pri << endl;
- cout << "_pro = " << _pro << endl;
- cout << "_pub = " << _pub << endl;
- }
- public:
- int _pub;
- protected:
- int _pro;
- private:
- int _pri;
- };
- class Derived :public Base
- {
- public:
- Derived(int Dpub = 3,int Dpro=4,int Dpri =5)
- :_Dpub(Dpub),
- _Dpro(Dpro),
- _Dpri(Dpri)
- {
- cout << "Derived()" << endl;
- }
- ~Derived()
- {
- cout << "~Derived()" << endl;
- }
- void ShowDerived()
- {
- cout << "_pro=" << _pro << endl;
- cout << "_Dpri = " << _Dpri << endl;
- cout << "_Dpro = " << _Dpro << endl;
- cout << "_Dpub = " << _Dpub << endl;
- }
- public:
- int _Dpub;
- protected:
- int _Dpro;
- private:
- int _Dpri;
- };
- void test0()
- {
- Derived d1;
- d1.ShowBase();
- d1.ShowDerived();
- d1._pub = 10;
- d1._Dpub = 11;
- d1.ShowBase();
- d1.ShowDerived();
- }
- int main()
- {
-
- test0();
- return 0;
- }
一下是单继承模式下Derived类继承Base类的之后的模型。
基类的成员变量在上面,派生类成员变量在基类下面。
运行结果:
总结:
1.基类的private成员在派生类是不能被访问的(不可见),如果基类成员不想在类外直接被访问,但需要在派生中能访问,就应该定义为protected。就可以看出保护成员限定符是因为继承才出现的。
2.public继承是一个接口继承,保持is—a原则,每个父类可用的成员对子类也可用,因为每个子类对象也是一个父类对象。
3.protected/private继承是一个实现继承,基类的部分成员并非完全成为子类接口的一部分,是has-a的关系
原则。
4.不管那种继承方式,在派生类内部都可以访问基类的公有成员和保护成员,基类的私有成员不管在哪种继承方式下在派生类都是不可见的。
5.使用关键字class时默认的继承方式是private,使用struct时默认的继承方式是public。(建议最好写出继承方式)
继承关系中构造函数的调用顺序:
编译器调用派生类构造函数---》转调基类构造函数---》再执行派生类构造函数体。
1.基类构造函数调用顺序按照继承列表中的顺序调用。
2.构造派生类 类成员时,按照在派生类中声明的次序调用。
【说明】
1.基类没有缺省构造函数,派生类必须要在初始列表中显示调用基类的构造函数。
2.基类如果没有定义构造函数,派生类也可以选择不定义,全部使用缺省构造函数。
3.如果基类没有缺省构造函数,派生类必须要定义一个构造函数,在初始化列表中显示调用基类构造函数。
继承关系中析构函数的调用过程:
派生类析构函数---》派生类包含成员对象析构函数(调用顺序和成员对象在基类中声明的顺序相反)--》基类析构函数(调用顺序和基类在派生列表中的声明顺序相反)
继承体系的作用域:
运行结果:
1.在继承体系中基类和派生类是两个不同的作用域。
2.子类和父类中有同名成员,子类成员将屏蔽对父类成员的直接访问。(在子类成员函数中,可以使用基类::基类成员 访问)构成同名隐藏---重定义。(在实际应用中,除非必要否则应尽量避免定义同名成员)
(1)同名隐藏和函数重载:
继承与转换--赋值兼容规则--(必须是public):
1.子类对象可以赋值给父类对象(切割/切片)
2.父类对象不能赋值给子类对象
3.父类指针或引用可以指向子类对象
4.子类的指针或引用不能指向父类对象(可以通过强制类型转换完成)
友元和静态成员与继承的关系:
1.友元关系不能继承,也就是基类友元不能访问子类私有和保护(友元函数并不是成员函数,所以并不能继承下来)
2.基类定义了static成员,则整个继承体系里面只有一个这样的成员。无论派生出多少个子类,都只有一个static成员实例(静态成员是属于类的,是所有对象共享一个)
单继承&&多继承&&菱形继承
单继承已在上面说明,我们看一下多继承的模型,一个类有两个及两个以上的直接父类时,称这个继承为多继承。
#include<iostream> using namespace std;
class Base { public: Base(int pub = 0, int pri = 1) :_pub(pub), _pri(pri) { cout << "Base()" << endl; } int _pub; private: int _pri;
}; class Base0 { public: Base0(int pub0 = 2, int pri0 = 3) :_pub0(pub0), _pri0(pri0) { cout << "Base0()" << endl; } int _pub0; private: int _pri0; }; class Deiverd:public Base,public Base0 { public: Deiverd(int Dpub = 4, int Dpri = 5) :_Dpub(Dpub), _Dpri(Dpri) { cout << "Deiverd()" << endl; } int _Dpub; private: int _Dpri; }; void test0() { Deiverd d1; } int main() { test0(); return 0; }
继承模型如下:
菱形继承:
#include<iostream> using namespace std;
class Base { public: Base(int pub = 0, int pri = 1) :_pub(pub), _pri(pri) { cout << "Base()" << endl; } int _pub; private: int _pri;
}; class Deiverd0:public Base { public: Deiverd0(int Dpub0 = 2, int Dpri0 = 3) :_Dpub0(Dpub0), _Dpri0(Dpri0) { cout << "Deiverd0()" << endl; } int _Dpub0; private: int _Dpri0; }; class Deiverd:public Base { public: Deiverd(int Dpub = 4, int Dpri = 5) :_Dpub(Dpub), _Dpri(Dpri) { cout << "Deiverd()" << endl; } int _Dpub; private: int _Dpri; }; class Final:public Deiverd0,public Deiverd { public: Final(int fpub = 7, int fpri = 8) :_fpub(fpub), _fpri(fpri) { cout << "Final()" << endl; } int _fpub; private: int _fpri; }; void test0() { Final f1; //f1._pub = 5; f1.Deiverd::_pub = 5; } int main() { test0(); return 0; }
菱形继承模型图分析:
根据内存分布情况画出抽象图:
通过上图可以看出基类Base在Final创建的对象里面一共保存了两份。 当你尝试用此语句:f1._pub=5;时编译器会报错
因为编译器并不知道你要访问是那一个_pub,是Deiverd继承来的?亦或是Deiverd0继承来的,所以编译器只能给你报出Final::_pub不明确;但是你可以通过语句:f1.Deiverd::_pub = 5;或者f1.Deiverd0::_pub = 5;来访问_pub。
菱形继承总结:
1.菱形继承存在明显的二义性。
2.菱形继承存在数据的冗余,造成空间的大量浪费。
3.在设计时尽量不要用菱形继承。
以上就是我关于继承部分的理解,关于菱形虚拟继承将在下一部分进行刨析,如果有那里不对的地方,还望不吝赐教,在下方留言或者私信我。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。