派生类构造函数
- 格式:doc
- 大小:23.00 KB
- 文档页数:2
前面我们说基类的成员函数可以被继承,可以通过派生类的对象访问,但这仅仅指的是普通的成员函数,类的构造函数不能被继承。
构造函数不能被继承是有道理的,因为即使继承了,它的名字和派生类的名字也不一样,不能成为派生类的构造函数,当然更不能成为普通的成员函数。
在设计派生类时,对继承过来的成员变量的初始化工作也要由派生类的构造函数完成,但是大部分基类都有private 属性的成员变量,它们在派生类中无法访问,更不能使用派生类的构造函数来初始化。
这种矛盾在C++继承中是普遍存在的,解决这个问题的思路是:在派生类的构造函数中调用基类的构造函数。
下面的例子展示了如何在派生类的构造函数中调用基类的构造函数:1.#include<iostream>ing namespace std;3.4.//基类People5.class People{6.protected:7.char*m_name;8.int m_age;9.public:10.People(char*,int);11.};12.People::People(char*name,int age):m_name(name),m_age(age){}13.14.//派生类Student15.class Student:public People{16.private:17.float m_score;18.public:19.Student(char*name,int age,float score);20.void display();21.};22.//People(name, age)就是调用基类的构造函数23.Student::Student(char*name,int age,float score):People(name, age),m_score(score){}24.void Student::display(){25.cout<<m_name<<"的年龄是"<<m_age<<",成绩是"<<m_score<<"。
1.什么是类的继承与派生?继承性是面向对象程序设计的第二个重要特性,通过继承实现了数据抽象基础上的代码重用。
继承是对许多问题中分层特性的一种自然描述,因而也是类的具体化和被重新利用的一种手段,它所表达的就是一种对象类之间的相交关系。
它使得某类对象可以继承另外一类对象的特征和能力。
继承所具有的作用有两个方面:一方面可以减少代码冗余;另一方面可以通过协调性来减少相互之间的接口和界面。
通过继承方式定义的子类也称为派生类。
2.类的三种继承方式之间的区别是什么?类的继承方式有public(公有)继承、protected(保护)继承和private(私有)继承三种。
对于不同的继承方式,会导致基类成员原来的访问属性在派生类中有所变化。
表5.1列出了不同继承方式下基类成员访问属性的变化情况。
表5.1 不同继承方式下基类成员的访问属性说明:该表第1列给出3种继承方式,第1行给出基类成员的3种访问属性。
其余单元格内容为基类成员在派生类中的访问属性。
从表中可以看出:(1) 基类的私有成员在派生类中均是不可访问的,它只能由基类的成员访问。
(2) 在公有继承方式下,基类中的公有成员和保护成员在派生类中的访问属性不变。
(3) 在保护继承方式下,基类中的公有成员和保护成员在派生类中均为保护的。
(4) 在私有继承方式下,基类中的公有成员和保护成员在派生类中均为私有的。
需要注意的是:保护成员与私有成员唯一的不同是当发生派生后,处在基类protected区的成员可被派生类直接访问,而私有成员在派生类中是不可访问的。
在同一类中私有成员和保护成员的用法完全一样。
3.派生类能否直接访问基类的私有成员?若否,应如何实现?派生类不能直接访问基类的私有成员。
具体实现方式:(1) 在类定义体中增加保护段为了便于派生类的访问,可以将基类私有成员中需提供给派生类访问的部分定义为保护段成员。
保护段成员可以被它的派生类访问,但是对于外界是隐藏起来的。
这样,既方便了派生类的访问,又禁止外界对它的派生类访问。
C++程序设计模拟试卷(一)一、单项选择题(本大题共20小题,每小题1分,共20分)在每小题列出的四个备选项中只有一个是符合题目要求的,请将其代码填写在题后的括号内。
错选、多选或未选均无分。
1. 编写C++程序一般需经过的几个步骤依次是()A. 编辑、调试、编译、连接B。
编辑、编译、连接、运行C. 编译、调试、编辑、连接D. 编译、编辑、连接、运行答案:B解析:经过编辑、编译、连接和运行四个步骤。
编辑是将C++源程序输入计算机的过程,保存文件名为cpp。
编译是使用系统提供的编译器将源程序cpp生成机器语言的过程,目标文件为obj,由于没有得到系统分配的绝对地址,还不能直接运行。
连接是将目标文件obj转换为可执行程序的过程,结果为exe。
运行是执行exe,在屏幕上显示结果的过程.1.基类的构造函数。
2.子对象的构造函数。
3.成员初始化表中的其他项.4.派生类构造函数的函数体。
2。
决定C++语言中函数的返回值类型的是()A。
return语句中的表达式类型B。
调用该函数时系统随机产生的类型C。
调用该函数时的主调用函数类型D. 在定义该函数时所指定的数据类型答案:D解析:函数的返回值类型由定义函数时的指定的数据类型决定的.A项的表达式的值要转换成函数的定义时的返回类型.3。
下面叙述不正确的是()A。
派生类一般都用公有派生B。
对基类成员的访问必须是无二义性的C. 赋值兼容规则也适用于多重继承的组合D. 基类的公有成员在派生类中仍然是公有的答案:D解析:继承方式有三种:公有、私有和保护.多继承中,多个基类具有同名成员,在它们的子类中访问这些成员,就产生了二义性,但进行访问时,不能存在二义性。
赋值兼容规则是指派生类对象可以当作基类对象使用,只要存在继承关系,所以单继承或多继承都适用。
基类中的公有成员采用私有继承时,在派生类中变成了私有成员,所以D项错误.4。
所谓数据封装就是将一组数据和与这组数据有关操作组装在一起,形成一个实体,这实体也就是()A。
构造函数的执⾏顺序⼀、C#中构造函数有⼏种。
1.静态构造函数2.默认构造函数3.带参数的构造函数⼆、顺序如何执⾏呢?先看代码:class MyClass{static MyClass(){Console.WriteLine("静态构造函数被调⽤。
");}private static Component staticField = new Component("静态字段被实例化。
");private Component instanceField = new Component("实例成员字段被实例化。
");public MyClass(){Console.WriteLine("对象构造函数被调⽤。
");}}//此类型⽤于作MyClass类的成员//此类型在实例化的时候可以再控制台输出⾃定义信息,以给出相关提⽰class Component{public Component(String info){Console.WriteLine(info);}}class Program{static void Main(string[] args){MyClass instance = new MyClass();Console.Read();}} 运⾏结果:1.静态字段被实例化2.静态构造函数被调⽤3.实例成员字段被实例化4.对象构造函数被调⽤再来看看带基类的构造函数是如何运⾏class Base{static Base(){Console.WriteLine("基类静态构造函数被调⽤。
");}private static Component baseStaticField = new Component("基类静态字段被实例化。
");private Component baseInstanceField = new Component("基类实例成员字段被实例化。
c++派生类的构造函数C++是一门面向对象的编程语言,它允许程序员使用类和对象来封装数据和行为。
在C++中,派生类是基于已存在的类(称为基类)创建的一种新类。
派生类从基类继承了数据和方法,并且还可以添加新的属性和方法。
在C++中,派生类的构造函数是指创建派生类对象时所调用的函数。
派生类的构造函数负责初始化派生类对象中从基类继承的成员和派生类自己添加的成员。
本文将详细介绍C++派生类的构造函数。
在C++中,派生类的构造函数必须调用基类的构造函数,以初始化从基类继承的成员变量。
在创建派生类对象时,首先创建基类对象,然后再对派生类对象进行初始化。
1. 构造函数必须有与类名相同的名称。
2. 构造函数可以有参数,也可以没有参数。
3. 派生类必须调用基类的构造函数,以初始化从基类继承的成员变量。
下面是一个基类Person和一个派生类Student的定义:```cppclass Person{protected:string name;int age;public:Person(){}void setName(string n){name = n;}void setAge(int a){age = a;}};在定义派生类Student的时候,通过public继承了基类Person。
此时,派生类的构造函数必须调用基类的构造函数,以初始化从基类继承的成员变量name和age。
派生类新增加了一个成员变量grade,需要在自己的构造函数中进行初始化。
派生类构造函数可以有多种调用方式,具体如下:1. 用基类构造函数初始化列表初始化派生类对象初始化列表是C++语言提供的一种简洁的初始化成员变量的语法。
它使用冒号(:)后接一个以逗号分隔的初始化列表,在其中对派生类和基类成员变量进行初始化。
下面是Student类中使用初始化列表对基类成员变量进行初始化的方法:在上面的代码中,派生类Student的构造函数使用冒号后接一个初始化列表来初始化基类成员变量name和age。
派生类的构造函数及其对象的初始化由于构造函数不能被继承,因此,派生类的构造函数中除了对派生类中数据成员进行初始化外,还必须通过调用直接基类的构造函数来对基类中数据成员初始化,一般地将,对派生类中数据成员初始化放在该派生类构造函数的函数体内,而调用基类构造函数的基类中数据成员初始化放在该构造函数的成员初始化表中。
派生类构造函数的格式如下表示:<派生类构造函数名>(<参数表>) : <成员初始化表>{<派生类构造函数的函数体>}其中,<派生类构造函数名>同该派生类的类名。
<成员初始化表>中包含如下的初始化项:①基类的构造函数,用来给基类中数据成员初始化;②子对象的类的构造函数,用来给派生类中子对象的数据成员初始化;③派生类中常成员的初始化。
<派生类构造函数的函数体>用来给派生类中的数据成员初始化。
派生类构造函数的调用顺序如下:①基类构造函数;②子对象的构造函数;③成员初始化表中其他初始化项;④派生类构造函数的函数体。
在基类中有默认构造函数时,派生类的构造函数中可隐含调用基类中的默认构造函数。
派生类中析构函数由于析构函数也不能继承,因此派生类的析构函数中将调用直接基类的析构函数。
执行派生类析构函数的顺序正好与指向派生类的构造函数的顺序相反。
先调用派生类的析构函数,再调用子对象类的析构函数,最后调用直接基类的析构函数。
例如:分析下列程序的输出结果,掌握派生类构造函数的定义格式和执行顺序,以及派生类析构函数的调用方法。
#include<iostream>using namespace std;class A{int x;protected: int y;public: int z;A(int a,int b,int c){x=a;y=b;z=c;}//定义构造函数基类初始化int Getx(){return x;} //定义成员函数返回xint Gety(){return y;} //返回yvoid ShowA(){cout<< "x="<<x<<'\t'<<"y="<<y<<'\t'<<"z="<<z<<'\n';}};class B:public A{int m,n;public: B(int a,int b,int c,int d,int e):A(a,b,c){m=d;n=e;} //派生类的构造函数void Show(){cout<<"m="<<m<<'\t'<<"n="<<n<<'\n';cout<<"x="<<Getx()<<'\t'<<"y="<<y<<'\t'<<"z="<<z<<'\n'; }int Sum(){return ( Getx()+y+z+m+n);}};int main(void){B b1(1,2,3,4,5);b1.ShowA(); b1.Show();cout<< "Sum="<<b1.Sum()<<'\n';cout<<"x="<<b1.Getx()<<'\t';cout << "y=" <<b1.Gety()<<'\t'; cout << "z="<<b1.z<<'\n';return 0;}。
派生类构造函数
派生类的数据成员由所有基类的数据成员与派生类新增的数据成员共同组成,如果派生类新增成员中包括其他类的对象(子对象),派生类的数据成员中实际上还间接包括了这些对象的数据成员。
因此,构造派生类的对象时,必须对基类数据成员、新增数据成员和成员对象的数据成员进行初始化。
派生类的构造函数必须要以合适的初值作为参数,隐含调用基类和新增对象成员的构造函数,来初始化它们各自的数据成员,然后再加入新的语句对新增普通数据成员进行初始化。
派生类构造函数的一般格式如下:
<派生类名>::<派生类名>(<参数表>) : <基类名1>(<参数表1>),
……,
<基类名n>(<参数表n>),
<子对象名1>(<参数表n+1>),
……,
<子对象名m>(<参数表n+m>)
{
<派生类构造函数体> //派生类新增成员的初始化
}
说明:
(1) 对基类成员和子对象成员的初始化必须在成员初始化列表中进行,新增成员的初始化既可以在成员初始化列表中进行,也可以在构造函数体中进行。
(2) 派生类构造函数必须对这三类成员进行初始化,其执行顺序如下所述。
. 调用基类构造函数;
. 调用子对象的构造函数;
. 派生类的构造函数体;
(3) 当派生类有多个基类时,处于同一层次的各个基类的构造函数的调用顺序取决于定义派生类时声明的顺序(自左向右),而与在派生类构造函数的成员初始化列表中给出的顺序无关。
(4) 如果派生类的基类也是一个派生类,则每个派生类只需负责其直接基类的构造,依次上溯。
(5) 当派生类中有多个子对象时,各个子对象构造函数的调用顺序也取决于在派生类中定义的顺序(自前至后),而与在派生类构造函数的成员初始化列表中给出的顺序无关。
(6) 派生类构造函数提供了将参数传递给基类构造函数的途径,以保证在基类进行初始化时能够获得必要的数据。
因此,如果基类的构造函数定义了一个或多个参数时,派生类必须定义构造函数。
(7) 如果基类中定义了缺省构造函数或根本没有定义任何一个构造函数(此时,由编译器自动生成缺省构造函数)时,在派生类构造函数的定义中可以省略对基类构造函数的调用,即省略"<基类名>(<参数表>)"。
(8) 子对象的情况与基类相同。
(9) 当所有的基类和子对象的构造函数都可以省略时,可以省略派生类构造函数的成员初始化列表。
(10) 如果所有的基类和子对象构造函数都不需要参数,派生类也不需要参数时,派生类构造函数可以不定义。
(11) 派生类不能继承基类的构造函数和析构函数。