不同继承方式下对基类成员的访问控制和使用虚基类解决多重继承的二义性

合集下载

C++继承机制

C++继承机制

C++继承机制继承继承是类与类之间的一种关系定义:“类B继承类A”,或者说“类A派生类B”类B中除了自己定义的成员之外,还自动包括了类A中定义的数据成员与成员函数,这些自动继承下来的成员称为类B的继承成员。

一、继承的语法1、class 派生类名: 基类类名表{public: 公有成员说明列表;protected: 受保护成员说明列表;private: 私有成员说明列表;};其中基类类名表的格式为:access 基类类名1, ……, access 基类类名naccess为继承访问控制符,规定了派生类对基类的继承方式,可为public,private或者protected,继承访问控制符可省略,此时认为为private在protected后定义的是保护段,其中的数据成员或成员函数称为受保护成员:具有公有成员与私有成员的双重角色。

2、一个类的受保护成员,对于其子孙类(派生类)的成员函数来说是公有的,对类本身及后代类之外定义的其他函数则是私有成员。

3、派生类可以重新定义基类的成员函数,覆盖基类的同名函数4.通过类名限定符在派生类中使用基类的同名成员二、继承访问控制规则公有继承(公有派生)、私有继承、保护派生类的对象不仅存放了在派生类中定义的非静态数据成员,而且也存放了从基类中继承下来的非静态数据成员。

二、类型兼容性1.赋值运算的类型兼容性类型的赋值兼容性规则:1) 允许将后代类的对象赋值给祖先类,但反之不成立。

例:BASE obj1;Y1 obj2;obj1 = obj2 ; // 把obj2中基类部分的内容赋给obj1obj2 = obj1 ;但此规则只适用于公有派生,只有公有派生类才能兼容基类类型2) 指向基类对象的指针也可指向公有派生类对象2.参数传递与对象初始化的类型兼容性与赋值运算类型兼容性相同A* p=q;//初始化A*p;P=q; //赋值继承与构造函数、析构函数一、构造函数与析构函数的调用次序1. 构造函数的调用次序在创建一个派生类的对象时先调用其基类的构造函数再调用本类对象成员的构造函数最后才调用本类的构造函数2. 析构函数的调用次序先调用本类的析构函数再调用本类对象成员的析构函数最后才调用其基类的析构函数二、向基类构造函数传递实际参数给基类构造函数传递实际参数是通过向派生类构造函数传递实际参数以及初始化列表来间接实现传递的。

c++解决多继承的原理

c++解决多继承的原理

C++解决多继承的原理一、简介多继承是面向对象编程中的一个重要概念,它允许一个类从多个父类中继承属性和方法。

然而,多继承在C++中可能会引发一些问题,例如菱形问题(也称为钻石问题)。

为了解决这些问题,C++引入了一些特殊的规则和机制。

本文档将详细介绍C++解决多继承的原理。

二、多继承的基本概念在C++中,一个类可以有一个或多个父类,这些父类被称为基类。

子类继承了父类的所有公有和保护成员。

子类的对象可以被视为父类的对象,这意味着它可以被赋值给指向父类对象的指针。

三、多继承的问题1. 菱形问题:当两个类A和B都继承自一个共同的基类C,然后类D同时继承自A和B时,就可能出现菱形问题。

如果类C中的某个成员函数在类D中被重写,那么这个成员函数在调用时应该调用哪个版本呢?这就是菱形问题。

2. 虚基类问题:如果一个类从多个基类中继承了同一个成员,那么这个成员在类中只有一个实例。

这就是虚基类问题。

四、C++解决多继承的原理1. 虚基类:C++通过引入虚基类来解决虚基类问题。

虚基类是一种特殊的基类,它的目的就是让一个类从多个基类中继承同一个成员时,这个成员在类中只有一个实例。

在C++中,如果一个类的直接或间接基类中有一个或多个虚基类,那么这个类的构造函数必须初始化所有的虚基类。

2. 虚拟继承:C++通过引入虚拟继承来解决菱形问题。

虚拟继承是一种特殊类型的继承,它允许一个类从多个基类中继承,但是只会产生一个虚基类实例。

在C++中,如果一个类的直接或间接基类中有一个是虚拟的,那么这个类的构造函数必须初始化这个虚拟基类。

3. 构造函数和析构函数:C++规定,当创建一个对象时,构造函数按照声明顺序依次调用;当销毁一个对象时,析构函数按照声明逆序依次调用。

因此,如果一个类的直接或间接基类中有虚基类或虚拟基类,那么这些基类的构造函数和析构函数必须按照正确的顺序调用。

4. 内存布局:当一个类通过多继承派生出子类时,子类的对象将包含所有基类的成员变量。

C++多继承的二义性问题

C++多继承的二义性问题

C++多继承的二义性问题
在多重继承中,需要解决的主要问题是标识符不唯一,即二义性问题。

比如,当在派生类继承的多个基类中有同名成员时,派生类中就会出现标识符不唯一的情况。

在多重继承中,派生类由多个基类派生时,基类之间用逗号隔开,且每个基类前都必须指明继承方式,否则默认是私有继承。

可以通过以下3种方法解决二义性问题。

使用运算符"::";
使用同名覆盖的原则;
使用虚基类;
1. 使用域运算符
如果派生类的基类之间没有继承关系,同时又没有共同的基类,则在引用同名成员时,可以在成员名前面加上类名和域运算符来区别来自不同基类的成员。

2.使用同名覆盖的原则
在派生类中重新定义与基类中同名的成员(如果是成员函数,则参数表也要相同,否则是重载)以屏蔽掉基类中的同名成员,在引用这些同名成员时,引用的就是派生类中的成员。

#include
using namespace std;
class Base
{
public:
int x;
void show()
{
cout
3.虚基类
在多重继承中,要引用派生类的成员时,先是在派生类自身的作用域内寻找,如果找不到再到基类中寻找。

这时,如果这些基类有一个共同的基类,派生类访问这个共同基类的成员时,就有可能由于同名成员的问题而发生二义性,此时就需要虚基类来解决。

【免费下载】多重继承与虚继承

【免费下载】多重继承与虚继承

main.cpp:13: error: candidates are: void Base2::print(int)
main.cpp:6: error:
void Base1::print()
main.cpp:25: error: request for member `display' is ambiguous
#include <iostream>
class Base1 { public:
void print() {} void display() {} void show() {} };
class Base2 { public:
void print(int) {} void show(int); private: void display(int) {} };
通常,每个类只初始化自己的直接基类。在应用于虚基类的时候,这个初始化策略会失败。如果使用 常规规则,就可能会多次初始化虚基类。类将沿着包含该虚基类的每个继承路径初始化。
为了解决这个重复初始化问题,从具有虚基类的类继承的类对初始化进行特殊处理。在虚派生中,由 最低层派生类的构造函数初始化虚基类。
虽然由最低层派生类初始化虚基类,但是任何直接或间接继承虚基类的类一般也必须为该基类提供自 己的初始化式。只要可以创建虚基类派生类类型的独立对象,该类就必须初始化自己的虚基类,这些初始 化式只在创建中间类型的对象时使用。
void print() { std::cout << "D2" << std::endl;
} };
class DD: public D1, public D2 { };
int main () { DD d; d.print();

C++第5章习题参考答案

C++第5章习题参考答案

1.什么是类的继承与派生?继承性是面向对象程序设计的第二个重要特性,通过继承实现了数据抽象基础上的代码重用。

继承是对许多问题中分层特性的一种自然描述,因而也是类的具体化和被重新利用的一种手段,它所表达的就是一种对象类之间的相交关系。

它使得某类对象可以继承另外一类对象的特征和能力。

继承所具有的作用有两个方面:一方面可以减少代码冗余;另一方面可以通过协调性来减少相互之间的接口和界面。

通过继承方式定义的子类也称为派生类。

2.类的三种继承方式之间的区别是什么?类的继承方式有public(公有)继承、protected(保护)继承和private(私有)继承三种。

对于不同的继承方式,会导致基类成员原来的访问属性在派生类中有所变化。

表5.1列出了不同继承方式下基类成员访问属性的变化情况。

表5.1 不同继承方式下基类成员的访问属性说明:该表第1列给出3种继承方式,第1行给出基类成员的3种访问属性。

其余单元格内容为基类成员在派生类中的访问属性。

从表中可以看出:(1) 基类的私有成员在派生类中均是不可访问的,它只能由基类的成员访问。

(2) 在公有继承方式下,基类中的公有成员和保护成员在派生类中的访问属性不变。

(3) 在保护继承方式下,基类中的公有成员和保护成员在派生类中均为保护的。

(4) 在私有继承方式下,基类中的公有成员和保护成员在派生类中均为私有的。

需要注意的是:保护成员与私有成员唯一的不同是当发生派生后,处在基类protected区的成员可被派生类直接访问,而私有成员在派生类中是不可访问的。

在同一类中私有成员和保护成员的用法完全一样。

3.派生类能否直接访问基类的私有成员?若否,应如何实现?派生类不能直接访问基类的私有成员。

具体实现方式:(1) 在类定义体中增加保护段为了便于派生类的访问,可以将基类私有成员中需提供给派生类访问的部分定义为保护段成员。

保护段成员可以被它的派生类访问,但是对于外界是隐藏起来的。

这样,既方便了派生类的访问,又禁止外界对它的派生类访问。

OOP第6部分__多重继承

OOP第6部分__多重继承

17
17.5 多重继承的构造函数
江 西 财 经 大 学 信 息 学 院
派生类与基类中构造函数的调用顺序是先调用基类的构造函 数对基类成员进行初始化。然后执行派生类的构造函数,如 果基类仍是派生类,则这个过程递归进行。 当派生类还包括对象成员时,则基类的构造函数先被调用, 对象成员的构造函数次之,最后执行派生类的构造函数。在 有多个对象成员的情况下,这些对象成员的调用顺序取决于 它们在派生类中被说明的顺序。
17.3 二义性及其支配规则
江 西 财 经 大 学 信 息 学 院
二义性:对某个成员访问不能唯一确定 二义性产生的原因:不同类的成员可以同名 规定:在多继承、多层次的继承结构中,总是逐层往上、访问 最靠近自己的那个同名成员。但是,如果在同一层的两个类中 具有同名成员,则产生二义性。 具体来讲: 什么是二义性:当一个派生类是多重派生也就是由多个基类派 生而来时,假如这些基类中的成员有成员名相同的情况,如果 使用一个表达式引用了这些同名的成员,就会造成无法确定是 引用哪个基类的成员,这种对基类成员的访问就是二义性的。 8
obj.B::func( );
//A的func( );
//B的func( );
10
作用域规则
江 西 财 经 大 学 信 息 学 院
C++作用域规则:就是当基类中的成员名字在派生 类中再次声明,则派生类中的名字就屏蔽掉基类中 相应的名字(也就是派生类的自定义成员与基类成员 同名时,派生类的成员优先)。那么如果要使用被屏 蔽的成员呢? 这就要由作用域分辨操作符实现,形式是 : 类名::类标识符 作用域分辨不仅可以用在类中,而且可以用在函数 调用时。
如果一个派生类从多个基类中派生,而这些基类又有一个共 同的基类,则在这个派生类中访问这个共同基类中的成员时 会产生两义性。

跟我学C++语言编程技术——多重多级继承及虚基类

跟我学C++语言编程技术——多重多级继承及虚基类

本讲的回顾
在本讲的最后对本讲做一个简要的回顾
C++语言程序设计及编程技术
多重多级继承及虚基类
第七讲、多重多级继承及虚基类 在本单元中您能了解如下知识点: 继承时的二义性产生的时机 同名支配原则 虚基类的编程规则 虚基类方式继承时的构造函数设计规则
访问的二义性
访问时的二义性: 对某一函数调用时将有多种可能的形式出现。 class Window { public: Window(); Window(int x=0, int y=0, int h=600, int w=800); }; void main() { Window winA; //此时系统不知将调用那一种形式的构造函数来实现 初始化,这是典型的访问时的二义性问题。但在多重 多级继承时还会产生另一种形式的访问时的二义性问时,基类与派生类之间或基类之间出现 同名成员时,将出现访问时的二义性。这可采用 类名指定或支配原则来解决访问时的二义性问题。
同名支配(覆盖)原则
派生类中的成员名覆盖基类中的同名成员; 调用时未强行指明时则为派生类中的同名成员; 如访问被覆盖的同名基类成员,应使用基类名加 以限定。
在多级继承时的二义性
派生类从多个基类继承派生,而这些基类又从同一 个基类派生,则在访问此共同基类中的成员时, 将产生二义性(类似生物学中的“近亲繁殖”)--这可以通过采用虚基类的机制来解决。
虚基类
含义:在派生类的定义时以virtual加以修饰的基类 。 定义的语法:请见文档P50。 作用:它主要用来解决多重与多级继承时可能发生的 对同一基类继承多次而产生访问的二义性问题,为最 远的派生类提供一份基类的成员而不重复对它产生多 次拷贝,因为此时编译系统将采用优化的编译方式来 处理各级派生类的成员。 如何判断是否为虚基类的问题:画出多重与多级继承 时的各个类的继承关系链,观察是否有从某一个共同 的起点出发,经过不同的途径,最后又汇合在一处的 结点;此共同的起点(基类)应为虚基类。 处理的方法:应该将此共同的起点基类设计为虚基类。

青岛农业大学成人教育《面向对象程序设计》期末考试复习题及参考答案

青岛农业大学成人教育《面向对象程序设计》期末考试复习题及参考答案

46. 一个函数功能不太复杂,但要求被频繁调用,选用_______ 。( A )
A. 内联函数
B. 重载函数
C. 递归函数
D. 嵌套函数
47. 在 C++中使用流进行输入输出,其中用于屏幕输出的对象是_______ 。( C )
A. cerr B. cin C. cout D. cfile
48. 对 C++语言和 C 语言的兼容性,描述正确的是_______ 。( A )
A.友元函数的实现必须在类的内部定义 B.友元函数是类的成员函数
C.友元函数破坏了类的封装性和隐藏性 D.友元函数不能访问类的私有成员
27.下面叙述不正确的是________ 。(A)
A.基类的保护成员在派生类中仍然是保护成员
B.基类的保护成员在公有派生类中仍然是保护成员
C.基类的保护成员在私有派生类中是私有成员
A.public B. protected C.private D. static
35. C++中的类有两种用法:一种是类的实例化,即生成类对象,并参与系统的运行;
另一种是通过_______派生了新的类。 ( B )
A.复用
B.继承
C.封装
D.引用
36. 下列对派生类的描述中,错误的是_______ 。( D )
class Foo {ing bar ;};
则 Foo 类的成员 bar 是_________(C)
A.公有数据成员 B.公有成员函数 C.私有数据成员
D.私有成员函数
15.下列表示引用的方法中,__________是正确的。已知:int m=10; (D)
A. float &t=&m; B.int &y=10;
  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
计算机1307陈坤1305110094
};
class motorcycle:public bicycle,public motorcar
{
public:
motorcycle(){cout<<"motorcycle默认构造函数被调用"<<endl;}
~motorcycle(){cout<<"motorcycle析构函数被调用"<<endl;}
void stop(){cout<<"程序停止运行"<<endl;}
vehicl(){cout<<"vehicl默认构造函数被调用"<<endl;}
~vehicl(){cout<<"vehicl析构函数被调用"<<endl;}
};
class bicycle:public virtual vehicl
实验报告6
一、实验任务:
1、定义一个车(vehicl)基类,具有MaxSpeed、Weight等成员变量,run、stop等成员函数,由此派生出自行车(bicycle)类、汽车(motorcar)类。自行车(bicycle)类有高度(Height)等属性,汽车(motorcar)类有座位数(SeatNum)等属性。从bicycle和motorcar派生出摩托车(motorcycle)类,在继承过程中,注意把vehicl设置为虚基类。否则会有什么问题?
二、实验步骤:
1、编写程序定义一个车(vehicl)基类,由此派生出自行车(bicycle)类、汽车(motorcar)类,注意把vehicl设置为虚基类。再从bicycle和motorcar派生出摩托车(motorcycle)类,在main中测试这个类。
2、编译成功后,把vehicl类设置为非虚基类,再编译一次,此时系统报错,无法编译成功。因为若不把vehicl类设置为虚基类,会出现二义性错误,程序不能成功编译。
};
void main()
{
vehicl v;
v.run();
v.stop();bicyLeabharlann le b;b.run();
b.stop();
motorcar r;
r.run();
r.stop();
motorcycle e;
e.run();
e.stop();
}
运行结果:
注:若把基类设置为非虚基类会出现二义性错误,程序不能成功编译!
{
public:
int h;
bicycle(){cout<<"bicycle默认构造函数被调用"<<endl;}
~bicycle(){cout<<"bicycle析构函数被调用"<<endl;}
};
class motorcar:public virtual vehicl
{
public:
int n;
motorcar(){cout<<"motorcar默认构造函数被调用"<<endl;}
三、本次实验难点:
在不同继承方式下对基类成员的访问控制和使用虚基类解决多重继承的二义性问题为本次实验的重点和难点,要在实验前后着重阐述。
源程序:
#include<iostream>
using namespace std;
class vehicl
{
public:
int v;
int m;
void run(){cout<<"程序开始运行"<<endl;}
相关文档
最新文档