多重继承引起的二义性问题和虚基类

多重继承容易引起的问题就是因为继承的成员同名而产生的二义性问题。

例:类A和类B中都有成员函数display和数据成员a,类C是类A和类B的直接派生类

情况一:

cpp 复制代码
class A
{
    public:
        int a;
        void display();
};
class B
{
    public:
        int a;
        void display;
};
class C:public A,public B//公用继承
{
    public:
        int b;
        void show();
};

如果在main函数中定义类C的对象c1并调用数据成员a和成员函数display

cpp 复制代码
C c1;
c1.a=3;//引用c1的数据成员a
c1.dispaly();//调用c1的成员函数display

由于基类A和基类B都有数据成员a和成员函数display,编译系统无法判别要访问的是哪一个基类的成员,因此,程序编译出错。

解决方法1、用基类名来限定

cpp 复制代码
c1.A::a=3;//引用c1对象中的基类A的数据成员a
c2.A::display();//引用c1的成员函数display

若派生类C中的成员函数show访问基类A的display和a,可以不必写对象名而直接写

cpp 复制代码
c1.A::A=3;//引用c1对象中的基类A的数据成员a
c1.A::display();//调用c1对象中的基类A的成员函数display

不同的成员函数,只有在函数名和参数个数相同、类型相匹配的情况下才发生同名覆盖,如果只有函数名相同而参数不同,不会发生同名覆盖,而属于函数重载。

虚基类的作用:

C++提供虚基类的方法,使得在继承间接共同基类时只保留一份成员。

使用虚基类发方法:

class A//声明基类A

{.........};

class B:virtual public A//声明类B是类A的公用派生类,A是B的虚基类

{......};

class C:virtual public A//声明类C是类A的公用派生类,A是C的虚基类

{......};

注意:++虚基类并不是在声明基类时声明的,而是在声明派生类时,指定继承方式时声明的。++

声明虚基类的一般形式为:

class 派生类名:virtual 继承方式 基类名

经过上面的声明后,当基类通过多条派生路径被一个派生类继承时,该派生类只继承该基类一次,也就是说,基类成员只保留一次。

二、虚基类的初始化

class A//定义基类A

{

A(int i){}//基类构造函数,有一个参数

.......};

class B:virtual public A//A作为B的虚基类

{

B(int n):A(n){}//类B构造函数,在初始化表中对虚基类初始化

...};

class C:virtual public A//A作为C的虚基类

{

C(int n):A(n){}

......};//类C的构造函数,在初始化表中对虚基类初始化

class D:public B,public C//类D的构造函数,在初始化表中对所有基类初始化

{

D(int n):A(n),B(n),C(n){}

......};

应用:

cpp 复制代码
#include<iostream>
#include<string>
using namespace std;
class Person
{
public:
	Person(string nam, char s, int a) {
		name = nam;
		sex = s;
		age = a;
	}
protected:
	string name;
	char sex;
	int age;
};
class Teacher :virtual public Person
{
public:
	Teacher(string nam, char s, int a, string t) :Person(nam, s, a)
	{
		title = t;
	}
protected:
	string title;
};
class Student :virtual public Person
{
public:
	Student(string nam, char s, int a, float sco) :Person(nam, s, a)
	{
		score = sco;
	}
protected:
	float score;
};
class Graduate :virtual public Teacher, public Student//Teacher和Student为直接基类
{
public:
	Graduate(string nam, char s, int a, string t, float sco, float w) :Person(nam, s, a), Teacher(nam, s, a, t), Student(nam, s, a, sco)
	{
		wage = w;
	}
	void show()
	{
		cout << "name:" << name << endl;
		cout << "age:" << age << endl;
		cout << "sex:" << sex << endl;
		cout << "title:" << title << endl;
		cout << "score:" << score << endl;
		cout << "wage:<" << wage << endl;
	}
private:
	float wage;
};
int main()
{
	Graduate grad1("yan_tong", 'f', 24, "saadistant", 99.9, 3000);
	grad1.show();

	return 0;
}

运行结果:

相关推荐
Dream Cosmos5 分钟前
Linux 多线程——线程互斥:从抢票问题到 Mutex 底层原理
linux·c++
hahaha60166 分钟前
HLS高层次综合设计技巧--循环merge和循环split
人工智能·算法·计算机视觉
JAI科研7 分钟前
Deepseek Agent Harness教程(七) | Deepseek Harness不是一个内核加一堆插件
开发语言·人工智能·深度学习·算法·自然语言处理·transformer·vllm
集思广益的灰太狼24 分钟前
变频器启动致PLC数据异常?西门子G120配合滤波器EMC抑制方案
人工智能·算法·工控·emc·电磁兼容·变频器·西门子
孙克旭_34 分钟前
单链表进阶实操:5 道常考面试题详细解析【Java 实现】
java·开发语言·数据结构·单链表
Titan202435 分钟前
HTTPS基础知识梳理
服务器·网络·c++·网络协议·学习·http·https
艾莉丝努力练剑38 分钟前
【AI大模型接入SDK】SSE协议
c++·学习·面试·大模型·sdk
斑马13939 分钟前
Linux软件编程学习笔记(五)——线程
开发语言·php
方方洛39 分钟前
vllm教程-03-架构设计
算法·架构
玄昌盛不会编程41 分钟前
LeetCode——2091. 从数组中移除最大值和最小值
java·算法·leetcode