继承(加深)-构造函数调用顺序与函数重定义
2017-10-11 11:48
330 查看
一、派生类的构造函数与析构函数
从基类派生子类时,基类的构造函数不能继承到派生类中,因此我们在定义派生类的构造函数时除了对自己的数据成员进行初始化外,还必须负责调用基类构造函数。如果派生类中有子对象,还应包含对子对象初始化的构造函数。
派生类构造函数一般的执行顺序为:
(1)最先调用基类的构造函数,多个基类则按派生类声明时列出的次序,从左到右调用,而不是初始化列表中的次序。
(2)再调用对象成员(子对象)的构造函数,按类声明中对象成员出现的次序调用,而不是初始化列表中的次序。
(3)最后执行派生类的构造函数。
下面我们看一段程序:
运行结果为:
上述程序中,类B是类A的派生类,该成员初始化列表的顺序是:先是基类A的构造函数,再是派生类B中子对象的构造函数,最后是B的构造函数。
如果类中包含对象成员呢?我们看看下面的程序:
运行结果如下:
可以看出:
类C派生出类D,但类C包含一个类A的对象a,类D中包含一个类B的对象b,所以语句“D d”,先执行基类C中对象a的构造函数,再执行基类C的构造函数,接着是D中对象b的构造函数,最后执行类D的构造函数。
析构函数,其顺序与执行构造函数时的顺序正好相反。即次序如下:
(1)最先执行派生类的析构函数
(2)再调用对象成员(子对象)的析构函数,按类声明中对象成员出现的逆序调用,而不是初始化列表中的次序。
(3)最后调用基类的析构函数,多个基类则按派生类声明时列出的逆序(从右到左)调用。
二、继承成员的重定义
继承成员的重定义是指重新修改继承成员函数的实现。
我们先来看一段代码:
运行结果为:
这是因为如果在派生类中增加一个函数原型与继承成员函数一模一样的成员函数,则该函数实现的函数体是对继承成员函数的重定义。
如果一个派生类的对象调用这个函数,首先在派生类中查找是否有该函数的定义,有则调用派生类中成员函数,否则才在所有的祖先类中查找。
三、友元关系不能继承
友元关系不能继承,也就是说基类友元不能访问子类私有和保护成员。除非在子类中也声明为友元。
四、静态成员数据
基类定义了static成员,则整个继承体系里面只有一个这样的成员。无论派生出多少个子类,都只有 一个static成员实例。
我们来看一个例子:
class Person
{
public:
Person()
{
++_count;
}
protected:
string _name;
public:
static int _count;
};
int Person::_count = 0;
class Student :public Person
{
protected:
int _num;
};
void TestPerson()
{
Person p;
Student s1;
Student s2;
Student s3;
cout << "人数:" << Person::_count << endl;
Student::_count = 0;
cout << "人数:" << Person::_count << endl;
}
int main()
{
TestPerson();
system("pause");
return 0;
}
这就可以看出来对象共用一个静态成员。
从基类派生子类时,基类的构造函数不能继承到派生类中,因此我们在定义派生类的构造函数时除了对自己的数据成员进行初始化外,还必须负责调用基类构造函数。如果派生类中有子对象,还应包含对子对象初始化的构造函数。
派生类构造函数一般的执行顺序为:
(1)最先调用基类的构造函数,多个基类则按派生类声明时列出的次序,从左到右调用,而不是初始化列表中的次序。
(2)再调用对象成员(子对象)的构造函数,按类声明中对象成员出现的次序调用,而不是初始化列表中的次序。
(3)最后执行派生类的构造函数。
下面我们看一段程序:
#include<iostream> using namespace std; class A { public: A() { cout << "A Constructor1" << endl; } A(int i) { x1 = i; cout << "A Constructor2" << endl; } void displaya() { cout << "x1=" << x1 << endl; } private: int x1; }; class B :public A //若为多继承,按从左到右的顺序调用 { public: B() { cout << "B Constructor1" << endl; } B(int i) :A(i + 10) { x2 = i; cout << "B Constructor2" << endl; } void displayb() { displaya(); cout << "x2=" << x2 << endl; } private: int x2; }; int main() { B b(2); b.displayb(); system("pause"); return 0; }
运行结果为:
上述程序中,类B是类A的派生类,该成员初始化列表的顺序是:先是基类A的构造函数,再是派生类B中子对象的构造函数,最后是B的构造函数。
如果类中包含对象成员呢?我们看看下面的程序:
class A { public: A() { cout << "class A" << endl; } }; class B { public: B() { cout << "class B" << endl; } }; class C { A a; public: C() { cout << "class C" << endl; } }; class D :public C { B b; public: D() { cout << "class D" << endl; } }; int main() { D d; system("pause"); return 0; }
运行结果如下:
可以看出:
类C派生出类D,但类C包含一个类A的对象a,类D中包含一个类B的对象b,所以语句“D d”,先执行基类C中对象a的构造函数,再执行基类C的构造函数,接着是D中对象b的构造函数,最后执行类D的构造函数。
析构函数,其顺序与执行构造函数时的顺序正好相反。即次序如下:
(1)最先执行派生类的析构函数
(2)再调用对象成员(子对象)的析构函数,按类声明中对象成员出现的逆序调用,而不是初始化列表中的次序。
(3)最后调用基类的析构函数,多个基类则按派生类声明时列出的逆序(从右到左)调用。
二、继承成员的重定义
继承成员的重定义是指重新修改继承成员函数的实现。
我们先来看一段代码:
class A { int i; public: void set(int x) { i = x; } void disp() { cout << "i=" << i << endl; } }; class B { int j; public: void set(int y) { j = y; } void disp() { cout << "j=" << j << endl; } }; int main() { A a; B b; a.set(1); //调用类A的set函数 a.disp(); b.set(2); //调用类B的set函数 b.disp(); system("pause"); return 0; }
运行结果为:
这是因为如果在派生类中增加一个函数原型与继承成员函数一模一样的成员函数,则该函数实现的函数体是对继承成员函数的重定义。
如果一个派生类的对象调用这个函数,首先在派生类中查找是否有该函数的定义,有则调用派生类中成员函数,否则才在所有的祖先类中查找。
三、友元关系不能继承
友元关系不能继承,也就是说基类友元不能访问子类私有和保护成员。除非在子类中也声明为友元。
四、静态成员数据
基类定义了static成员,则整个继承体系里面只有一个这样的成员。无论派生出多少个子类,都只有 一个static成员实例。
我们来看一个例子:
class Person
{
public:
Person()
{
++_count;
}
protected:
string _name;
public:
static int _count;
};
int Person::_count = 0;
class Student :public Person
{
protected:
int _num;
};
void TestPerson()
{
Person p;
Student s1;
Student s2;
Student s3;
cout << "人数:" << Person::_count << endl;
Student::_count = 0;
cout << "人数:" << Person::_count << endl;
}
int main()
{
TestPerson();
system("pause");
return 0;
}
这就可以看出来对象共用一个静态成员。
相关文章推荐
- 继承与派生,多继承,函数重载,构造函数调用顺序 静态多态和动态多态
- C++继承中构造函数、析构函数调用顺序及虚函数的动态绑定
- 继承与派生,多继承,函数重载,构造函数调用顺序
- C++继承中构造函数、析构函数调用顺序及虚函数的动态绑定
- C#类的继承,构造函数实现及其调用顺序
- 虚函数 多重继承的构造函数的调用,虚函数地址的找法
- C++继承中构造函数、析构函数调用顺序及虚析构函数
- 理解C++存在继承和组合的对象构造函数调用顺序
- C++继承中析构函数 构造函数的调用顺序以及虚析构函数
- 多重继承和有内嵌对象时构造函数调用顺序
- java 构造函数 成员函数初始化顺序 以及多态的构造函数的调用顺序
- C++继承时子类定义同名成员变量时的调用继承函数的问题
- C++继承中构造函数、析构函数调用顺序及虚析构函数
- C++中多个类继承时构造函数与析构函数的调用顺序
- C++虚继承(七) --- 虚继承对基类构造函数调用顺序的影响
- 【c++继承】继承关系中派生类对象构造函数和析构函数调用顺序
- C++继承中析构函数 构造函数的调用顺序以及虚析构函数
- C++多重继承,菱形继承中构造函数的调用顺序
- java 构造函数 成员函数初始化顺序 以及多态的构造函数的调用顺序
- 继承中的构造函数调用顺序