C++类继承中,基类/当前对象属性/当前对象的构造顺序
2016-09-11 14:45
246 查看
[1]中提到,规范的派生类构造函数三个要点:
首先创建基类对象
应通过成员初始化列表,创建基类对象
应该初始化本派生类新增的成员变量
那在构造派生类实例的过程中,其基类(以及多继承的时候多个基类)/当前对象属性/当前对象的构造顺序如何呢?
下面初步分析:
其中,冒号指出C的基类是B1和B2,public限定符指出B1和B2都是公有基类,我们称之为公有派生[1]。
公有派生中,基类的公有成员(成员变量、成员方法)变成了派生类的公有成员。基类的私有成员变成了派生类的私有成员,但是不能直接访问,只能借助基类的public和protected方法访问。
这时,程序将使用基类默认构造函数。
也就是说C的写法相当于在成员初始化列表调用基类的默认构造函数:
B1和B2的构造顺序只和继承的顺序有关,和成员初始化列表中的顺序无关
调整继承顺序
更进一步可以把C中构造函数参数作为实参传递给基类构造函数:
修改C为:
构造子类实例过程中,依次进行如下构造:
构造基类
构造当前派生类的成员对象
构造当前派生类(执行自己的构造函数)
和基类很相似。
在成员初始化列表,如果不显式调用成员对象的构造函数,程序就会调用默认构造函数。显式调用,程序就会调用你指定的构造函数。
成员对象之间的构造顺序之和声明顺序有关,和在Member Initialization List中的顺序无关。
当然,也可以不指定初始化列表,在构造函数中再进行成员对象的赋值,这会导致成员对象被构造多次。 更重要的是,因为常量类型、引用类型的成员不接受赋值,它们只能在初始化列表中进行初始化。[2]
到这里,基类/当前对象属性/当前对象的构造顺序终于搞清楚了。
2 C++手稿:封装与继承
首先创建基类对象
应通过成员初始化列表,创建基类对象
应该初始化本派生类新增的成员变量
那在构造派生类实例的过程中,其基类(以及多继承的时候多个基类)/当前对象属性/当前对象的构造顺序如何呢?
下面初步分析:
1 不显式调用基类构造函数
C继承B1和B2#include<iostream> using namespace std; class B1 { public: B1(){ cout<<"B1"<<endl;} }; class B2 { public: B2(){cout<<"B2"<<endl;} }; class C:public B1,public B2 { public: C(){cout<<"C"<<endl;} }; int main() { C obj; return 0; } /*output B1 B2 C */
其中,冒号指出C的基类是B1和B2,public限定符指出B1和B2都是公有基类,我们称之为公有派生[1]。
公有派生中,基类的公有成员(成员变量、成员方法)变成了派生类的公有成员。基类的私有成员变成了派生类的私有成员,但是不能直接访问,只能借助基类的public和protected方法访问。
这时,程序将使用基类默认构造函数。
也就是说C的写法相当于在成员初始化列表调用基类的默认构造函数:
C():B1(),B2(){cout<<"C"<<endl;}。
B1和B2的构造顺序只和继承的顺序有关,和成员初始化列表中的顺序无关
调整继承顺序
class C:public B2,public B1,输出顺序为
B2 B1.而修改成员初始化列表中的顺序没有效果。
2 显式调用基类构造函数
同样的,B1和B2的构造顺序只和继承的顺序有关,和成员初始化列表中的顺序无关class B1 { public: B1(){ cout<<"B1"<<endl;} B1(int i){ cout<<"B1:"<<i<<endl;} }; class B2 { public: B2(){cout<<"B2"<<endl;} B2(int i){ cout<<"B2:"<<i<<endl;} }; class C:public B2,public B1 { public: C():B1(10),B2(20){cout<<"C"<<endl;} }; int main() { C obj; return 0; } /*output B2:20 B1:10 C */
更进一步可以把C中构造函数参数作为实参传递给基类构造函数:
C(int x,int y):B1(x),B2(y){cout<<"C"<<endl;}
3 封闭类
有成员对象的类称为封闭类,这是对象组合的一种实现方式[2]。修改C为:
class C:public B2,public B1 { private: int x; B1 memberb1; B2 memberb2; public: C():B1(10),B2(20){cout<<"C"<<endl;} }; /*output B2:20 B1:10 B1 B2 C */
构造子类实例过程中,依次进行如下构造:
构造基类
构造当前派生类的成员对象
构造当前派生类(执行自己的构造函数)
3.1 对当前对象属性使用成员初始化列表语法
当前对象属性就是成员对象。
class C:public B2,public B1 { private: int x; B1 memberb1; B2 memberb2; public: C():B1(10),B2(20),memberb1(1),memberb2(2){cout<<"C"<<endl;} }; /*output B2:20 B1:10 B1:1 B2:2 C */
和基类很相似。
在成员初始化列表,如果不显式调用成员对象的构造函数,程序就会调用默认构造函数。显式调用,程序就会调用你指定的构造函数。
成员对象之间的构造顺序之和声明顺序有关,和在Member Initialization List中的顺序无关。
当然,也可以不指定初始化列表,在构造函数中再进行成员对象的赋值,这会导致成员对象被构造多次。 更重要的是,因为常量类型、引用类型的成员不接受赋值,它们只能在初始化列表中进行初始化。[2]
到这里,基类/当前对象属性/当前对象的构造顺序终于搞清楚了。
Reference
1 C++ primer plus第六版2 C++手稿:封装与继承
相关文章推荐
- (1.4.1)虚继承、虚函数继承、多重继承和“含对象成员类的构造顺序”
- C++类和对象知识点整理七----虚基类和虚继承
- 虚继承基类构造顺序
- 基类指针创建子类对象 构造顺序 面试必考
- C++类继承--构造函数时先构造基类
- 基类子类子对象的构造与析构顺序
- 用构造函数继承基类的属性、用原型对象继承基类的方法
- 2018/01/08JAVA 基础 / 接口与继承/Java关键词:变量引用 super 调用父类对象方法/构造方法【或者访问父类对象属性】的方式归纳
- java继承:属性不具有多态性 和 return this 返回当前对象
- 关于java中子类,父类中,静态代码块: staic{},动态代码块:{},构造方法,类属性,对象属性等执行顺序做个总结:
- 面向对象银角大王补充2-self就是调用当前方法的对象-静态字段,公有属性-封装的理解-继承的理解,普通方法,静态方法
- Java对象的构造过程---子类继承父类时(非)静态块及构造函数等的执行顺序
- ECMAScript中冒充法不能继承基类的prototype属性
- 关于JAVA继承类的静态变量、成员变量、父子类构造方法调用顺序的探讨
- c++类定义体中定义继承树中类的对象问题
- 继承体系下的对象构造
- “无继承”情况下的对象构造
- 对象,构造函数的属性(prototype)的继承
- 对象的初始化顺序问题02(继承中)
- 类继承中构造方法与static块调用顺序浅析