继承知识汇总

》什么是继承:C++语言为了实现代码复用最重要的手段,允许我们在原有(基类)功能下扩增,形成一个新类,这个新类称为派生类或者子类。

》继承格式:class 派生类名(子类名):继承类型  基类名(父类名)

继承类型:基类成员在派生类中可见性(public,protected,private)

public继承:基类的非私有成员在子类中访问类型不变。

protected继承:基类的非私有成员在子类中访问类型变为protected属性。

private继承:基类的非私有成员在子类中访问类型都变为private属性。

不论何种继承基类的私有成员在派生类中都是继承下来的了只是都是不可见的。

几点总结:

1.基类私有成员在派生类中是不可访问的,如果想在派生类中访问基类非私有成员,而在类外不能访问就定义为protected继承。

2.public继承是一个接口继承保持is-a原则,每个父类可用的成员对子类也可用,每个子类对象也是一个父类对象。(即父类非私有成员皆为子类所用)

3.protected/private继承是一个实现继承,基类的部分成员并非完全成为子类接口的一部分,是 has-a 的关系原则,所以非特殊情况下不会使用这两种继承关系,在绝大多数的场景下使用的都是公有继承。(即子类从父类继承来的某些成员对外属性是保护或者私有)

4.不管是哪种继承方式,在派生类内部都可以访问基类的公有成员和保护成员,基类的私有成员存在但是在子类中不可见(不能访问)。

5.使用关键字class时默认的继承方式是private,使用struct时默认的继承方式public,不过最好显式的写出继承方式。

6.在实际运用中一般使用都是public继承,极少场景下才会使用protetced/private继承.

》讲一下继承的调用顺序:

基类构造函数->派生类中成员对象构造函数->派生类构造函数

按照继承列表调用       按照派生类中成员对象声明顺序调用

总结:1.基类构造函数没有缺省值,派生类必须要在初始化列表中显示的调用基类构造函数并给出参数。

2.若基类没有定义构造函数则派生类也不需要定义都使用默认的构造函数

3.基类定义了带有形参表的构造函数,则派生类就必须也要定义。

举个菱形继承的例子:(下面会讲到菱形继承)

class A

{

public:

A()

{

cout << "A()" << endl;

}

int data1;

};

class B:public A

{

public:

B()

{

cout << "B()" << endl;

}

private:

int data2;

};

class C:public A

{

public:

C()

{

cout << "C()" << endl;

}

private:

int data3;

};

class D :public B, public C

{

public:

D()

{

cout << "C()" << endl;

}

private:

int data4;

};

int main()

{

B b;

return 0;

}

这里程序执行结果为:A();

B();

创建了一个B类对象,先调用父类即A的构造函数然后再调用自己的构造函数。这里的构造函数什么都没做。

》继承体系的作用域:

1.父类与子类分属于两个作用域(所以父类的私有成员才不能被子类使用因为相当于类外调用父类的私有成员)

2.子类和父类有同名成员,子类成员将屏蔽父类对自己成员的直接访问 称为同名隐藏

在子类中除非使用    基类名::成员名   才会访问基类成员 称为重定义

》继承与转换 --赋值兼容规则(条件:必须是public继承)

1.子类对象可以复制给父类对象  Base b=Derive d;

2.父类对象不可以复制给子类对象。会越界

3.父类的指针,引用可以指向子类对象。Base *B;  B=&d;

4.子类的指针,引用不可以指向父类对象。

》友元与继承

友元关系不能继承:即基类友元不能访问子类私有和保护成员。

》继承和静态成员:

若基类定义了一个静态成员,则无论有派生多少个子类,仅有这么一个静态成员。

》三种类型的调用方法:分别是

单继承:即保持直线继承

class A{};  class B:public A{};   class C:public B {};

多继承:即子类可以使用多个继承类型继承多个父类

class A{}; class B{};   class C:public A,public C{};

菱形继承:

class A{};  class B:public A{};   class C:public A {}; class D:public B,public C{};

上面菱形继承程序例子:

如果在主函数中定义D d;结果会是

A();

B();

A();

C();

D();

这样类D中就会有重复的类A中的成员,访问data1就会产生二义性,编译都通不过,因为他不知道你要调用哪一个data1,当然也可以使用d.B::data1;或者d.C::data1;来决定是哪个data1,不过我们在这块有一个更好的方法,那就是虚基类。

》虚继承:如果一个类有多个直接基类,且直接基类又有共同基类,则最底层的派生类中会保留这个间接共同基类的成员多份同名成员。

解决方法:1.在派生对象名前加作用域标识符使他唯一的标识一个成员

2.使用虚基类:虚基类声明:

class 派生类名:virtual 继承方式 类名{}

如果派生类中只存在一份间接基类的拷贝,则没有二义性。

》虚基类的初始化:与普通多继承的初始化在语法上是一样的,只是构造函数的调用不一样

1.虚基类如果定义带有形参的构造函数,或者定义普通的构造函数,则整个继承结构中,所有直接或者间接的派生类都必须在构造函数的成员初始化列表中对虚基类构造函数的调用,以初始化在虚基类中定义的数据成员。

2.建立一个对象时,如果这个对象含有从虚基类中继承来的成员,则虚基类的成员是由最远派生类的构造函数通过调用虚基类的构造函数来进行初始化的。该派生类的其它基类对虚基类构造函数的调用都忽略。

3.若同一层次中同时包含非虚基类和虚基类,应先调用基类的构造函数在调用非虚基类的构造函数。

4.对于多个虚基类,构造函数的执行顺序仍然是先左后右,自上而下。

5.对于非虚基类,构造函数的执行顺序仍然是先左后右,自上而下。

6.若虚基类是由非虚基类派生而来的,则仍然先调用基类构造函数,再调用派生类构造函数。

还有一个问题,virtual这个关键词应该在哪加?所有派生类声明内都加还是只在直接派生类前加?弄清这个问题就要分析派生类的内存里都有些什么东西,是按照什么顺序存储的?

class A

{

public:

A(int a=0)

:data1(a)

{

cout << "A()" << endl;

}

int data1;

};

class B : virtual public A

{

public:

B(int b=0)

:A(1)

, data2(b)

{

cout << "B()" << endl;

}

private:

int data2;

};

int main()

{

B b(2);

return 0;

}

类B内存中有:指针P-》data2-》data1;并且P指向data1.

调试程序,看到在类B内首先是一个指针,其次是类B自己的成员data2最后是类A的成员data1,并且这个指针存放的就是类A中data1相对于类A对象的偏移量。

这也就是说,子类中会保存一个地址指向虚基类的成员。

还是这个例子,只是这里是虚继承:

class A

{

public:

A(int a=0)

:data1(a)

{

cout << "A()" << endl;

}

int data1;

};

class B : virtual public A

{

public:

B(int b=0)

:A(1)

, data2(b)

{

cout << "B()" << endl;

}

private:

int data2;

};

class C : virtual public A

{

public:

C(int c=0)

:A(3)

, data3(c)

{

cout << "C()" << endl;

}

private:

int data3;

};

class D : virtual public B,virtual public C

{

public:

D(int d=0)

:A(2)

,data4(d)

{

cout << "D()" << endl;

}

private:

int data4;

};

菱形虚继承:当直接子类与间接子类定义前都加virtual时:

分析类B的内存:指针P1-》data2-》data1;

类C的内存:指针P2-》data3-》data1;

类D的内存:指针P3-》data4-》data1-》P1-》data2-》P2-》data3;

P1 P2 P3

只有直接子类前有virtual时:

分析类B的内存:指针P1-》data2-》data1;

类C的内存:指针P2-》data3-》data1;

类D的内存:P1->data2-》P2-》data3-》data4-》data1;

时间: 2025-01-13 08:49:09

继承知识汇总的相关文章

沉淀,再出发:Java基础知识汇总

沉淀,再出发:Java基础知识汇总 一.前言 不管走得多远,基础知识是最重要的,这些知识就是建造一座座高楼大厦的基石和钢筋水泥.对于Java这门包含了编程方方面面的语言,有着太多的基础知识了,从最初的语法,对象的定义,类.接口.继承.静态.动态.重载.覆盖这些基本的概念和使用方法,到稍微高级一点的多线程,文件读写,网络编程,GUI使用,再到之后的反射机制.序列化.与数据库的结合等高级一点的用法,最后将设计模式应用其中,产生了一个个新的概念,比如Spring.Spring MVC.Hibernat

C++ 基础知识汇总 持续更新

摘录一些C++面试常考问题,写一些自己的理解,欢迎来摘果子. static关键字 用于声明静态对象: 静态函数只在本文件可见.(默认是extern的) 全局静态对象:全局静态对象,存储在全局/静态区,作用域整个程序,在程序结束才销毁: 局部静态对象:在函数内部加上static声明的变量,在首次调用时初始化,然后一直驻留在内存,作用域是该函数,可用于函数调用计数(primary有例子),程序结束释放: 静态数据成员:归属于类,类对象共享,类外初始化,类对象可访问: 静态函数成员:归属于类,只能访问

【转】ACM博弈知识汇总

博弈知识汇总 转自:http://www.cnblogs.com/kuangbin/archive/2011/08/28/2156426.html 有一种很有意思的游戏,就是有物体若干堆,可以是火柴棍或是围棋子等等均可.两个人轮流从堆中取物体若干,规定最后取光物体者取胜.这是我国民间很古老的一个游戏,别看这游戏极其简单,却蕴含着深刻的数学原理.下面我们来分析一下要如何才能够取胜. (一)巴什博奕(Bash Game):只有一堆n个物品,两个人轮流从这堆物品中取物,规定每次至少取一个,最多取m个.

JavaScript正則表達式知识汇总

Js 正則表達式知识汇总 正則表達式: 1.什么是RegExp?RegExp是正則表達式的缩写.RegExp 对象用于规定在文本中检索的内容. 2.定义RegExp:var +变量名=new RegExp(); 3.RegExp 对象有 3 个方法: 1)test()检索字符串中的指定值,返回值是true或false. var p1=new Reg("e"); document.write(Reg.test("welcome to China!")); 2)exec

Delphi基础知识汇总

☆Delphi基础数据类型 分类 范围 字节 备注 简单类型 序数 整数 Integer -2147483648 .. 2147483647 4 有符号32位 Cardinal 0 .. 4294967295 4 无符号32位 Shortint -128 .. 127 1 有符号8位 Smallint -32768 .. 32767 2 有符号16位 Longint -2147483648 .. 2147483647 4 有符号32位 Int64 -263 .. 263 8 有符号64位 Byt

动态规划 知识汇总

 Dp状态设计与方程总结 不完全状态记录 <1>青蛙过河问题 <2>利用区间 dp 背包类问题 <1> 0-1 背包,经典问题 <2>无限背包,经典问题 <3>判定性背包问题 <4>带附属关系的背包问题 <5> + -1 背包问题 <6>双背包求最优值 <7>构造三角形问题 <8>带上下界限制的背包问题(012背包) 线性的动态规划问题 <1>积木游戏问题 <2&g

Guava库学习:学习Guava Cache知识汇总

原文地址:Guava库学习:学习Guava Cache知识汇总 至此,我们结束了对Guava Cache 缓存机制的学习,在学习过程中,我们学习了如何简单的通过MapMaker创建最简单的ConcurrentMap缓存,我们也了解了缓存的高级特性,以及强大的LoadingCache,我们也探索和学习了CacheBuilder.CacheLoader这些核心的API,以及CacheStats.RemovalLitener等,下面对这些文章做一些汇总,方便以后的查阅和复习.     Guava库学习

PB编程基础知识汇总

PB编程基础知识汇总 第一章      1.  程序的开始,application的open事件. 退出程序例程:halt为退出函数 int SureQuit SureQuit = 2 SureQuit=Messagebox("退出系统","退出前请确认已保存好数据",Question!,OKCancel!, 2) if SureQuit = 1 then halt 2.  变量定义有效范围: ◎     declare-globe 全局变量,整个程序均有效 ◎  

ACM博弈知识汇总(转)

博弈知识汇总 有一种很有意思的游戏,就是有物体若干堆,可以是火柴棍或是围棋子等等均可.两个人轮流从堆中取物体若干,规定最后取光物体者取胜.这是我国民间很古老的一个游戏,别看这游戏极其简单,却蕴含着深刻的数学原理.下面我们来分析一下要如何才能够取胜. (一)巴什博奕(Bash Game):只有一堆n个物品,两个人轮流从这堆物品中取物,规定每次至少取一个,最多取m个.最后取光者得胜. 显然,如果n=m+1,那么由于一次最多只能取m个,所以,无论先取者拿走多少个,后取者都能够一次拿走剩余的物品,后者取