C++:派生类的构造函数和析构函数
4.2 派生类的构造函数和析构函数
4.2.1 派生类构造函数和析构函数的执行顺序
通常情况下,当创建派生类对象时,首先执行基类的构造函数,随后再执行派生类的构造函数;
当撤销派生类对象时,则先执行派生类的派生类的析构函数,随后再执行基类的析构函数。
//例4.5 派生类的构造函数和析构函的执行顺序
#include<iostream>
using namespace std;
class Base{ //声明基类Base
public:
Base()
{
cout<<"Constructor Base Class.."<<endl;
}
~Base()
{
cout<<"Destructor Base Class.."<<endl;
}
};
class Derived: public Base{ //声明基类Base的公有派生类Derived
public:
Derived()
{
cout<<"Constructor Derived Class.."<<endl;
}
~Derived()
{
cout<<"Destructor Derived Class.."<<endl;
}
};
int main()
{
Derived obj;
return ;
}
/*
说明:从程序运行的结果可以看出:构造函数的调用严格按照先调用基类的构造函数,后调用派生类的
构造函数的顺序执行。析构函数的调用顺序与构造函数的调用顺序正好相反,先调用派生类的析
构函数,再调用基类的析构函数。
*/
4.2.2 派生类构造函数和析构函数的构造规则
1. 简单的派生类的构造函数
当基类的构造函数没有参数,或没有显式定义构造函数时,派生类可以不向基类传递参数,甚至可以不定义构造函数。例4.5的程序就是由于基类的构造函数没有参数,所以派生类没有向基类传递参数。
派生类不能继承基类中构造函数和析构函数。当基类含有带参数的构造函数时,派生类必须定义构造函数,以提供把参数传递给基类构造函数的途径。
在C++中,派生类构造函数的一般格式为:
派生类名(参数总表):基类名(参数表)
{
派生类新增数据成员的初始化语句
}
其中,基类构造函数的参数,通常来源于派生类构造函数的参数总表,也可以用常数值。
//例4.6 当基类含有带参数的构造函数,派生类构造函数的构造方法。
#include<iostream>
#include<string>
using namespace std;
class Student{ //声明基类Student
public:
Student(int number1,string name1,float score1) //基类的构造函数
{
number = number1;
name = name1;
score = score1;
}
void print()
{
cout<<"number:"<<number<<endl;
cout<<"name:"<<name<<endl;
cout<<"score:"<<score<<endl;
}
protected:
int number;
string name;
float score;
};
class UStudent:public Student{ //基类Student的公有派生类UStudent
public:
UStudent(int number1,string name1,float score1,string major1)
:Student(,"张三",/*number1,name1,score1*/)
{ //定义派生类的构造函数时,缀上要调用的基类的构造函数及其参数
major = major1; //参数可以是派生类构造函数总参数表中的参数,也可以是常量和全局变量。
}
void print1()
{
print();
cout<<"major:"<<major<<endl;
}
private:
string major;
};
int main()
{
UStudent stu(,"张志",,"信息安全");
//stu.print();
stu.print1();
return ;
}
注意事项:
请注意派生类构造函数首行的写法:
UStudent(int number1,string name1,float score1,string major1):Student(number1,name1,score1)
冒号前面的部分是派生类构造函数的主干,它和以前介绍过的构造函数的形式相同,但它的总参数表中包括基类构造函数所需要的参数和对派生类新增的数据成员初始化所需要的参数。冒号后面的部分是要调用的基类构造函数及其参数。
从上面列出的派生类UStudent构造函数首行中可以看到,派生类构造函数名(UStudent)后面的总参数表中包括参数的类型和参数名(如 int number1),而基类构造函数的参数表中只有参数名而不包括参数类型(如 number1),因为在这里不是再定义基类构造函数,而是调用基类构造函数,因此这些参数是实参而不是形参。它们可以是派生类构造函数总参数表中的参数,也可以是常量和全局变量。
说明:1、可以将派生类构造函数定义在类的外部,而在类体内只写该函数的声明。如在例4.6的派生类中可以只写构造函数的声明:
UStudent(int number1,string name1,float score1,string major1)
而在类外定义派生类的构造函数:
UStudent::UStudent(int number1,string name1,float score1,string major1):Student(number1,name1,score1)
{
major = major1;
}
请注意:在类中声明派生类构造函数时,不包括基类构造函数及其参数表(Student(number1,name1,score1),只在
类外定义构造函数时才将它列出。
2、若基类使用默认构造函数或不带参数的构造函数,则在派生类中定义构造函数时, "基类构造函数名(参数表)"可以省略。
如在例4.5的程序中,由于基类的构造函数没有参数,所以在派生类中定义构造函数时,不要缀上":Base()",也即
不必写成:
Deirved:Base()
{
cout<<"Constructor derived class"<<endl;
}
3、当基类构造函数不带参数时,派生类不一定需要定义构造函数,然而当基类的构造函数哪怕只带有一个参数,它所有的派生类必须定义构造函数,甚至所定义的派生类构造函数的函数体可能为空,仅仅起到参数的传递作用。
例如,在下面的程序中,派生类Deruved就不使用参数n,n只是被传递给基类构造函数Base。
class Base{
public:
Base(int n)
{
i = n;
}
void show()
{
cout<<"i="<<i<<endl;
}
private:
int i;
};
class Derived public Base{
public:
Derived(int n):Base(n) //构造函数参数表中只有一个参数,
{ } //传递给了要调用的基类构造函数Base
}; //派生类构造函数体为空
2.派生类的析构函数
在派生类中可以根据需要定义自己的析构函数,用来对派生类中的所增加的成员进行清理工作。基类的清理工作仍然有基类的析构函数负责。由于析构函数是不带参数的,在派生类中是否要定义析构函数与它所属基类的析构函数无关。在执行派生类的析构函数时,系统会自动调用基类的析构函数,对基类的对象进行清理。析构函数的调用顺序与构造函数正好相反,先执行派生类的析构函数,再执行基类的析构函数。
//例4.7 简单派生类的构造函数和析构函数的执行顺序。
#include<iostream>
using namespace std;
class A{ //声明基类A
public:
A()
{
cout<<"Constuctor class A"<<endl; //基类的构造函数
}
~A()
{
cout<<"Destuctor class A"<<endl; //基类的构造函数
}
};
class B:public A{
public:
B()
{
cout<<"Constuctor class B"<<endl; //派生类的构造函数
}
~B()
{
cout<<"Destuctor class B"<<endl; //派生类的构造函数
}
};
int main()
{
B b;
return ;
}
/*
运行结果如下: Constuctor class A
Constuctor class B
Destuctor class B
Destuctor class A
*/
3.含有对象成员(子对象)的派生类的构造函数
当派生类中含有内嵌的对象成员(也称子对象)时,其构造函数的一般格式为:
派生类(参数总表):基类名(参数表 0):对象成员1(参数表 1),......,对象成员n(参数表 n)
{
派生类新增成员的初始化语句
}
在定义派生类对象时,构造函数的执行顺序如下:
(1)、调用基类的构造函数,对基类数据成员初始化;
(2)、调用内嵌对象成员的构造函数,对内嵌对象成员的数据成员进行初始化;
(3)、调用派生类的构造函数体,对派生类数据成员进行初始化。
撤销对象时,析构函数的调用顺序与构造函数的调用顺序相反,首先执行派生类的析构函数,
再执行内嵌对象成员的析构函数,最后执行基类的析构函数。
//例4.8 含有对象成员的派生类构造函数和析构函数的执行顺序
#include<iostream>
using namespace std;
class Base{ //声明基类Base
public:
Base(int i) //基类的构造函数
{
x = i;
cout<<"Constructor base class"<<endl;
}
~Base() //基类的析构函数
{
cout<<"Destructor base class"<<endl;
}
void show()
{
cout<<"x = "<<x<<endl;
}
private:
int x;
};
class Derived :public Base{ //声明基类Base的公有派生类Derived
public:
Derived(int i):Base(i),d(i) //派生类的构造函数,缀上要调用的基类构造函数和对象成员的构造函数
{
cout<<"Constructor Derived class"<<endl;
}
~Derived()
{
cout<<"Destructor Derived class"<<endl;
}
private:
Base d;
};
int main()
{
Derived obj();
obj.show();
return ;
}
/*
运行结果是:Constructor base class
Constructor base class
Constructor Derived class
x = 5
Destructor Derived class
Destructor base class
Destructor base class */
说明:
(1)在派生类中含有多个内嵌对象成员时,调用内嵌对象成员的构造函数顺序由它们在类中声明的顺序确定。
(2)如果派生类的基类也是一个派生类,每个派生类只需负责其直接基类数据成员。依次上溯。
//例4.9 含有多个对象成员的派生类构造函数的执行顺序。
#include<iostream>
#include<string>
using namespace std;
class Student{ //声明基类Base
public:
Student(int number1,string name1,float score1)
{
number = number1;
name = name1;
score = score1;
}
void print()
{
cout<<"学号:"<<number<<endl;
cout<<"姓名:"<<name<<endl;
cout<<"成绩:"<<score<<endl;
}
protected:
int number;
string name;
float score;
};
class UStudent:public Student{ //声明基类Student的公有派生类UStudent
public:
UStudent(int number1,string name1,float score1,int number2,string name2,float score2,
int number3,string name3,float score3,string major1):Student(number1,name1,score1),
auditor2(number3,name3,score3),auditor1(number2,name2,score2)
{
major = major1;
}
void print()
{
cout<<"正式生是:"<<endl;
Student::print();
cout<<"专业是:"<<major<<endl;
}
void print_auditor1()
{
cout<<"旁听生是:"<<endl;
auditor1.print();
}
void print_auditor2()
{
cout<<"旁听生是:"<<endl;
auditor2.print();
}
private:
string major; //专业
Student auditor1; //定义对象成员1(旁听生)
Student auditor2; //定义对象成员2(旁听生)
};
int main()
{
UStudent stu(,"张志",,,"王全安",,,"李倩倩",,"信息安全");
stu.print(); stu.print_auditor1();
stu.print_auditor2();
return ;
}
C++:派生类的构造函数和析构函数的更多相关文章
- 不可或缺 Windows Native (21) - C++: 继承, 组合, 派生类的构造函数和析构函数, 基类与派生类的转换, 子对象的实例化, 基类成员的隐藏(派生类成员覆盖基类成员)
[源码下载] 不可或缺 Windows Native (21) - C++: 继承, 组合, 派生类的构造函数和析构函数, 基类与派生类的转换, 子对象的实例化, 基类成员的隐藏(派生类成员覆盖基类成 ...
- C++学习之路—继承与派生(二):派生类的构造函数与析构函数
(根据<C++程序设计>(谭浩强)整理,整理者:华科小涛,@http://www.cnblogs.com/hust-ghtao转载请注明) 由于基类的构造函数和析构函数是不能被继承的,所以 ...
- C++:派生类的构造函数和析构函数的调用顺序
一.派生类 在C++编程中,我们在编写一个基类的派生类时,大致可以分为四步: • 吸收基类的成员:不论是数据成员还是函数成员,派生类吸收除基类的构造函数和析构函数之外的全部成员. • 改造基类函数:在 ...
- C++学习笔记(6)----基类和派生类的构造函数和析构函数的执行顺序
基类和派生类:构造函数和析构函数的执行顺序 在Visual Studio中,新建控制台工程,构造类如下: #include<iostream> using namespace std; c ...
- cc28c_demo.cpp,派生类的构造函数和析构函数-代码示范3
cc28c_demo.cpp,派生类的构造函数和析构函数-代码示范3 //派生类的构造函数和析构函数//派生类的构造函数(执行步骤)//--执行基类的构造函数//--执行成员对象的构造函数//--执行 ...
- c++, 派生类的构造函数和析构函数 , [ 以及operator=不能被继承 or Not的探讨]
说明:文章中关于operator=实现的示例,从语法上是对的,但逻辑和习惯上都是错误的. 参见另一篇专门探究operator=的文章:<c++,operator=>http://www.c ...
- c++学习笔记4,派生类的构造函数与析构函数的调用顺序(一)
測试源代码: //測试派生类的构造函数的调用顺序何时调用 //Fedora20 gcc version=4.8.2 #include <iostream> using namespace ...
- c++派生类中构造函数和析构函数执行顺序、判断对象类型、抽象类、虚函数
一. 代码: 1 #include<stdio.h> 2 #include<string.h> 3 #include<algorithm> 4 #include&l ...
- c++ 单继承派生类的构造函数
1.派生类的构造函数: #include <iostream> #include<string> using namespace std; class Student//声明基 ...
随机推荐
- 植物大战僵尸中文第二版和年度版 游戏分析及delphi源码
00413184 |. E8 77E30100 |CALL PlantsVs.00431500 ; 地上的物品00413189 |. 8D7424 10 ...
- jQuery实现分页
转载地址 http://www.cnblogs.com/xiaoruoen/archive/2012/01/11/2318199.html ;( function($){ $.extend({ &qu ...
- Ajax入门小例子
大牛文章:http://www.cnblogs.com/guduoduo/p/3681296.html ---Ajax基础学习 http:/ ...
- string和stringBuilder的区别
曾经被问到过这个问题,回答得不是很好,在网上找了一下,园子里有大神很详细地讨论了二者的区别. http://www.cnblogs.com/yunfeng8967/articles/1093832.h ...
- unity项目实现“再按一次退出程序”提示功能
unity项目,再按一次退出程序,按第一次做提示,再按一次,程序退出. float _waitTime = 2f;//前后两次按退出间隔时间 void OnGUI() { ) { GUI.Label( ...
- c++程序开发利器
c++程序开发利器 vc6visual stdio系列都很好,个人最喜欢vc6,主要原因是快捷,classview和wizardbar功能强大,其他vs秒杀其他的vs windbgWinDbg是在wi ...
- Configuring My Site in SharePoint 2010
Configuring the User Profile Service in SharePoint 2010 http://sharepointgeorge.com/2010/configuring ...
- tomcat绑定域名
现在很多的公司的网站都是用tomcat作为应用服务区的,可是对于初学者,8080端口号是如何去掉的,这些网站是如何和域名绑定到一起的呢?一个tomcat是如何绑定多域名?并且这些域名是如何对应不同的项 ...
- ASP.Net MVC4 登录
一月之前,工作室师兄给我们介绍博客,然后试着去申请了一个,一直不晓得更新什么,直到今天,才有了一点小想法.最近在做一个小网站,然后就在登录那一块犯愁了,止步不前. 以前对登录一直没有什么概念,以为登录 ...
- ELF
http://www.360doc.com/content/11/0826/13/7588214_143424472.shtml 链接,装载都是基于数据结构ELF.