-
不是虚继承的情况下,实例化子类对象的时候,要分别执行其2个父类的父类构造函数,再分别执行2个父类的构造函数,因为继承关系中,必须实例化父类对象后(执行父类的构造函数)才能实例化子类对象(执行子类的构造函数),销毁的时候也要分别执行这个子类2个父类的析构函数及父类各自的父类的析构函数。<br> 用了虚继承后只执行一次爷爷构造函数一次爸爸构造函数(2个爸爸构造函数都只执行一次)一次孙子构造函数,爷父孙析构函数也是只执行一次。<br> 虚继承的情况下菱形继承作为最顶层的父类并没有进行参数的传递,也就是参数只使用了顶层父类的默认参数而无法从子类中获得传入的参数 正因为继承了2个爷爷的数据成员才能给他赋2个值,如果只有1个数据成员就只能得到一个值。继承到2个值是因为2个爸爸类分别继承爷爷类的数据成员,在继承给孙子类,孙子类就得到了2个爷爷类的数据成员,本质上是爸爸类分别有一个爷爷类的数据成员。(用虚继承解决)查看全部
-
公共继承一个类会造成类的重定义,要用宏定义来解决 #ifndef PERSON_H #define PERSON_H ...... ...... #endif 在菱形定义中一定会出现重定义,常用宏定义的方法来解决查看全部
-
菱形继承会导致数据冗余,一个对象中会有两份同一父类的数据。用虚继承可以解决冗余问题。就是两个爸爸类用虚公有继承的方式继承同一个父类,然后孙子类按照多继承的方式(写法)继承两个爸爸类,就可以只继承到一个爷爷类的数据,若不用虚公有继承的方式,就会导致孙子类继承到2个重复的爷爷类数据成员或者成员函数查看全部
-
还有个用初始化列表方式初始化成员的情况是初始化对象成员的时候查看全部
-
多继承的子类要用初始化列表的方式初始化子类的成员列表,实例化子类对象的时候,先执行父类的构造函数,父类的构造函数的执行顺序按照初始化成员列表的先后顺序执行。<br> 析构函数的执行顺序和构造函数的执行顺序相反 用初始化列表比较好的情况:传给构造函数的值要分别传给几个对象处理的时候,用 const 修饰的成员的时候,还有就是当初对象成员的时候。查看全部
-
多继承是一个对象继承多个对象,多重继承是一个对象层层继承上一个对象就像是孙子通过多重继承爷爷一样。每个子类都是父类的一个对象(isA),孙子也可以是爷爷的一个对象(也是 isA 关系) 实例化孙子类,会先执行爷爷的构造函数,在执行爸爸的构造函数,最后执行孙子的构造函数。销毁的时候,按照构造函数的逆序执行,先执行孙子的析构函数,在执行爸爸的析构函数,最后执行爷爷的析构函数。查看全部
-
私有继承查看全部
-
保护继承-protected查看全部
-
公有继承-public查看全部
-
注意:父类的指针只能访问父类的数据成员和成员函数,不能访问子类独有的数据成员以及成员函数。<br> 虚构函数: 继承,isA,释放子类内存。<br> 子类是父类的一个对象(isA)因此子类可以给父类赋值,就像5是 int 型,5 是 int 的其中一个成员,因此5可以赋给 int,从存储上来看,子类继承父类而且子类还有自有的数据成员和成员函数,子类给父类赋值时,就会将包含父类的那部分数据成员和成员函数赋给父类,剩下的就丢失,因为是给父类赋值,因此只要保证父类的值正确又没有缺失就行了,但是如果用父类给子类赋值,就无法给子类独有的数据成员和成员函数赋值,也就是不可控,这是不可行的。 请十分注意:这里写 person *p = new Soldier; p-> play(); 创建的是父类的指针,调用 play() 的时候调用的是父类的 play(),并不能调用到 子类的 play()<虽然这里子类没有自己的 play 而是从父类继承来 play ,如果有子类的 play ,将不能通过父类的 指针 调用到子类的 play >;(这点十分重要,在多态的虚函数中会遇到类似的问题)查看全部
-
实参是对象的时候,就会临时开辟一个对象,因此会执行相应的构造函数和析构函数,如果参数是对象的引用就不会执行构造函数和析构函数,参数是指针与此相同,后面2种没有产生新的临时变量,因此效率更高。查看全部
-
子类给父类赋值,或者子类初始化父类,或者用父类指针指向子类对象,都是将子类数据的值赋给父类<br> 父类的对象或者是指针只能调用父类自有的数据成员或者成员函数,无法调用子类的数据成员或者成员函数<br> 销毁的时候只执行父类的析构函数,子类的析构函数没执行,就会造成内存的泄露,这就需要用到虚析构函数;<br> 需要用到虚析构函数:当存在继承关系,使用父类的指针指向堆中的子类对象,又要用父类的指针释放这段内存。<br> 在父类析构函数前加上 virtual 就会被继承给子类。这样子类的析构函数实际上前面也有关键字 virtual ,即子类的析构函数也是虚析构函数。<br> 这样销毁的时候,先执行子类的虚构函数,在执行父类的虚构函数。 注意:父类的指针只能访问父类的数据成员和成员函数,不能访问子类独有的数据成员以及成员函数!查看全部
-
子类 isA 父类,或者 派生类 isA 基类,可以通过子类赋值实例化父类对象,但是不能用父类实例化子类。也可以用父类的指针指向子类对象,但是不能用子类的指针指向父类对象。综合来说,只能子类给父类赋值。因此可以将形参设置成父类对象或者父类的指针或者父类的引用,这样就可以接受子类对象的赋值,也可以接受父类对象的赋值。其中,指针接受地址,引用接收对象。 将子类的对象赋值给父类对象(或者说用子类的对象初始化父类对象),本质就是将子类从父类中继承的成员赋值给父类对象,子类的其他数据成员就会被截断(因为父类对象只能接受自己原来拥有的数据)。如果是父类的指针指向子类对象,父类指针也只能访问父类拥有的数据成员,无法访问子类独有的数据成员及成员函数。查看全部
-
即使子类的函数有参数而父类的同名函数没有参数,这两个函数也是存在隐藏关系的,子类对象仍然只能调用子类这个成员函数,而不能调用父类继承来的那个同名函数,若要调用,仍然要采用 子类对象.父类类名::同名函数 的方式调用父类继承来的那个掩藏函数。也就是说,隐藏函数之间无法形成重载,只能隐藏。查看全部
-
#include<> 用<>包含的文件,系统会到程序相应的默认库中去寻找<br><br> #include"" 用""包含的文件,系统会到本程序的目录下去寻找<br> 子类继承父类的函数和子类的函数同名,那么父类的函数会被隐藏,实例化子类的对象能访问到子类的这个函数,却不能访问到父类的这个同名函数,要访问父类的同名函数,要用 .子类对象.父类类名::同名函数 的方式访问到父类的同名函数, :: 可以理解为<br> ** 下的 成员。从而区分来准确找到所要访问的成员。对于数据成员的隐藏也是如此。<br> 一般不做数据成员的隐藏,而是采用有区别的命名方式区分父类和子类不同的数据成员。查看全部
举报
0/150
提交
取消