• linkedu视频
  • 平面设计
  • 电脑入门
  • 操作系统
  • 办公应用
  • 电脑硬件
  • 动画设计
  • 3D设计
  • 网页设计
  • CAD设计
  • 影音处理
  • 数据库
  • 程序设计
  • 认证考试
  • 信息管理
  • 信息安全
菜单
linkedu.com
  • 网页制作
  • 数据库
  • 程序设计
  • 操作系统
  • CMS教程
  • 游戏攻略
  • 脚本语言
  • 平面设计
  • 软件教程
  • 网络安全
  • 电脑知识
  • 服务器
  • 视频教程
  • JavaScript
  • ASP.NET
  • PHP
  • 正则表达式
  • AJAX
  • JSP
  • ASP
  • Flex
  • XML
  • 编程技巧
  • Android
  • swift
  • C#教程
  • vb
  • vb.net
  • C语言
  • Java
  • Delphi
  • 易语言
  • vc/mfc
  • 嵌入式开发
  • 游戏开发
  • ios
  • 编程问答
  • 汇编语言
  • 微信小程序
  • 数据结构
  • OpenGL
  • 架构设计
  • qt
  • 微信公众号
您的位置:首页 > 程序设计 >C语言 > 深入解析C++中派生类的构造函数

深入解析C++中派生类的构造函数

作者: 字体:[增加 减小] 来源:互联网 时间:2017-05-28

通过本文主要向大家介绍了c++派生类构造函数,c++派生类,c++类的继承与派生,c++继承与派生,c++继承与派生实例等相关知识,希望对您有所帮助,也希望大家支持linkedu.com www.linkedu.com

基类的构造函数不能被继承,在声明派生类时,对继承过来的成员变量的初始化工作也要由派生类的构造函数来完成。所以在设计派生类的构造函数时,不仅要考虑派生类新增的成员变量,还要考虑基类的成员变量,要让它们都被初始化。

解决这个问题的思路是:在执行派生类的构造函数时,调用基类的构造函数。

下面的例子展示了如何在派生类的构造函数中调用基类的构造函数。

#include<iostream>
using namespace std;
//基类
class People{
protected:
  char *name;
  int age;
public:
  People(char*, int);
};
People::People(char *name, int age): name(name), age(age){}
//派生类
class Student: public People{
private:
  float score;
public:
  Student(char*, int, float);
  void display();
};
//调用了基类的构造函数
Student::Student(char *name, int age, float score): People(name, age){
  this->score = score;
}
void Student::display(){
  cout<<name<<"的年龄是"<<age<<",成绩是"<<score<<endl;
}
int main(){
  Student stu("小明", 16, 90.5);
  stu.display();
  return 0;
}
</div>

运行结果为:
小明的年龄是16,成绩是90.5

请注意代码第23行:

Student::Student(char *name, int age, float score): People(name, age)
</div>


这是派生类 Student 的构造函数的写法。冒号前面是派生类构造函数的头部,这和我们以前介绍的构造函数的形式一样,但它的形参列表包括了初始化基类和派生类的成员变量所需的数据;冒号后面是对基类构造函数的调用,这和普通构造函数的参数初始化表非常类似。

实际上,你可以将对基类构造函数的调用和参数初始化表放在一起,如下所示:

Student::Student(char *name, int age, float score): People(name, age), score(score){}
</div>


基类构造函数和初始化表用逗号隔开。

需要注意的是:冒号后面是对基类构造函数的调用,而不是声明,所以括号里的参数是实参,它们不但可以是派生类构造函数总参数表中的参数,还可以是局部变量、常量等。如下所示:

Student::Student(char *name, int age, float score): People("李磊", 20)
</div>


基类构造函数调用规则

事实上,通过派生类创建对象时必须要调用基类的构造函数,这是语法规定。也就是说,定义派生类构造函数时最好指明基类构造函数;如果不指明,就调用基类的默认构造函数(不带参数的构造函数);如果没有默认构造函数,那么编译失败。

请看下面的例子:

#include<iostream>
using namespace std;
//基类
class People{
protected:
  char *name;
  int age;
public:
  People();
  People(char*, int);
};
People::People(){
  this->name = "xxx";
  this->age = 0;
}
People::People(char *name, int age): name(name), age(age){}
//派生类
class Student: public People{
private:
  float score;
public:
  Student();
  Student(char*, int, float);
  void display();
};
Student::Student(){
  this->score = 0.0;
}
Student::Student(char *name, int age, float score): People(name, age){
  this->score = score;
}
void Student::display(){
  cout<<name<<"的年龄是"<<age<<",成绩是"<<score<<endl;
}
int main(){
  Student stu1;
  stu1.display();
  Student stu2("小明", 16, 90.5);
  stu2.display();
  return 0;
}
</div>

运行结果:

xxx的年龄是0,成绩是0
小明的年龄是16,成绩是90.5
</div>


 

创建对象 stu1 时,执行派生类的构造函数 Student::Student(),它并没有指明要调用基类的哪一个构造函数,从运行结果可以很明显地看出来,系统默认调用了不带参数的构造函数,也就是 People::People()。

创建对象 stu2 时,执行派生类的构造函数 Student::Student(char *name, int age, float score),它指明了基类的构造函数。

在第31行代码中,如果将 People(name, age) 去掉,也会调用默认构造函数,stu2.display() 的输出结果将变为:
xxx的年龄是0,成绩是90.5

如果将基类 People 中不带参数的构造函数删除,那么会发生编译错误,因为创建对象 stu1 时没有调用基类构造函数。

总结:如果基类有默认构造函数,那么在派生类构造函数中可以不指明,系统会默认调用;如果没有,那么必须要指明,否则系统不知道如何调用基类的构造函数。
构造函数的调用顺序

为了搞清这个问题,我们不妨先来看一个例子:

#include<iostream>
using namespace std;
//基类
class People{
protected:
  char *name;
  int age;
public:
  People();
  People(char*, int);
};
People::People(): name("xxx"), age(0){
  cout<<"PeoPle::People()"<<endl;
}
People::People(char *name, int age): name(name), age(age){
  cout<<"PeoPle::People(char *, int)"<<endl;
}
//派生类
class Student: public People{
private:
  float score;
public:
  Student();
  Student(char*, int, float);
};
Student::Student(): score(0.0){
  cout<<"Student::Student()"<<endl;
}
Student::Student(char *name, int age, float score): People(name, age), score(score){
  cout<<"Student::Student(char*, int, float)"<<endl;
}
int main(){
  Student stu1;
  cout<<"--------------------"<<endl;
  Student stu2("小明", 16, 90.5);
  return 0;
}
</div>

运行结果:

PeoPle::People()
Student::Student()
--------------------
PeoPle::People(char *, int)
Student::Student(char*, int, float)
</div>

从运行结果可以清楚地看到,当创建派生类对象时,先调用基类构造函数,再调用派生类构造函数。如果继承关系有好几层的话,例如:
A --> B --> C
那么则创建C类对象时,构造函数的执行顺序为:
A类构造函数 --> B类构造函数 --> C类构造函数
构造函数的调用顺序是按照继承的层次自顶向下、从基类再到派生类的。

C++有子对象的派生类的构造函数
类的数据成员不但可以是标准型(如int、char)或系统提供的类型(如string),还可以包含类对象,如可以在声明一个类时包含这样的数据成员:

  Student s1; //Student是已声明的类名,s1是Student类的对象
</div>


这时,s1就是类对象中的内嵌对象,称为子对象(subobject),即对象中的对象。


那么,在对数据成员初始化时怎样对子对象初始化呢?请仔细分析下面程序,特别注意派生类构造函数的写法。

[例] 包含子对象的派生类的构造函数。为了简化程序以易于阅读,这里设基类Student的数据成员只有两个,即num和name。

#include <iostream>
#include <string>
using namespace std;
class Student//声明基类
{
public: //公用部分
  Student(int n, string nam ) //基类构造函数,与例11.5相同
  {
   num=n;
   name=nam;
  }
  void display( ) //成员函数,输出基类数据成员
  {
   cout<<"num:"<<num<<endl<<"name:"<<name<<endl;
  }
protected: //保护部分
  int num;
  string name;
};
class Student1: public Student //声明公用派生类Student1
{
public:
  Student1(int n, string nam,int n1, string nam1,int a, string ad):Student(n,nam),monitor(n1,nam1) //派生类构造函数
  {
   age=a;
   addr=ad;
  }
  void show( )
  {
   cout<<"This student is:"<<endl;
   display(); //输出num和name
   cout<<"age: "<<age<<endl; //输出age
   cout<<"address: "<<addr<<endl<<endl; //输出addr
  }
  void show_monitor( ) //成员函数,输出子对象
  {
   cout<<endl<<"Class monitor is:"<<endl;
   monitor.display( ); //调用基类成员函数
  }
private: //派生类的私有数据
  Student monitor; //定义子对象(班长)
  int age;
  string addr;
};
int main( )
{
  Student1 stud1(10010,"Wang-li",10001,"Li-sun",19,"115 Beijing Road,Shanghai");
  stud1.show( ); //输出学生的数据
  stud1.show_mo



 
分享到:QQ空间新浪微博腾讯微博微信百度贴吧QQ好友复制网址打印

您可能想查找下面的文章:

  • C++派生访问说明符小记(推荐)
  • C++ 类中有虚函数(虚函数表)时 内存分布详解
  • 浅谈C++中派生类对象的内存布局
  • C++聚合关系类的构造函数的调用顺序详解
  • 解析C++中多层派生时的构造函数及一些特殊形式
  • 深入解析C++中派生类的构造函数
  • 深入分析C++派生类中的保护成员继承
  • 解析C++中派生的概念以及派生类成员的访问属性
  • 解读C++编程中派生类的构成和创建
  • c++制作的时间函数类

相关文章

  • 2017-05-28C++删除链表中间节点的方法
  • 2017-05-28如何使用递归和非递归方式反转单向链表
  • 2017-05-28C++ 面试题翻译电话号码实例代码
  • 2017-05-28VC读配置文件实例
  • 2017-05-28C/C++指针小结
  • 2017-05-28C++插入排序算法实例
  • 2017-05-28详解C++中对构造函数和赋值运算符的复制和移动操作
  • 2017-05-28C++基础入门教程(四):枚举和指针
  • 2017-05-28C语言中获取文件状态的相关函数小结
  • 2017-05-28C语言double和float 实例分析

文章分类

  • JavaScript
  • ASP.NET
  • PHP
  • 正则表达式
  • AJAX
  • JSP
  • ASP
  • Flex
  • XML
  • 编程技巧
  • Android
  • swift
  • C#教程
  • vb
  • vb.net
  • C语言
  • Java
  • Delphi
  • 易语言
  • vc/mfc
  • 嵌入式开发
  • 游戏开发
  • ios
  • 编程问答
  • 汇编语言
  • 微信小程序
  • 数据结构
  • OpenGL
  • 架构设计
  • qt
  • 微信公众号

最近更新的内容

    • C语言结构体指针(指向结构体的指针)详解
    • C语言实现字符转unix时间戳的简单实例
    • C++遍历文件夹获取文件列表
    • C++ 字符串去重排序实例代码
    • linux根据pid获取进程名和获取进程pid(c语言获取pid)
    • C语言中字符的输入输出以及计算字符个数的方法详解
    • C++ 使用Json封装数据和解析数据
    • 提高C++程序运行效率的10个简单方法
    • getdate()函数的用法实例
    • 一些C语言中字符串的算法问题解决实例小结

关于我们 - 联系我们 - 免责声明 - 网站地图

©2020-2025 All Rights Reserved. linkedu.com 版权所有