C++多重继承、纯虚函数和抽象类

本文探讨了多重继承中基类构造与析构的问题及解决办法——使用虚基类,并介绍了纯虚函数与抽象类的概念。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

重载继承的初始化

1)如果类A和类B都同时继承自类X,类C继承自A和B,那么在创建类C的时候,类X的构造和析构函数

会被执行两次,因为类C在创建的时候,分别会去创建类A和类B,而类A和类B又会去创建类X,所以

就类X会被创建两次

2)如果类X中有函数Fun,那么类C在调用的时候需要指定调用哪个父类所继承的Fun函数,例如:c->A::Fun()

class X
{
public:
	X(){}
	virtual ~X(){}
	virtual void Fun()
	{
		cout<<"Class X"<<endl;
	}
};
class A:public X
{
public:
	A(int i):a(i){}
	virtual ~A(){}
	virtual void print()
	{
		cout<<"Class A - "<<a<<endl;
	}
private:
	int a;
};

class B:public X
{
public:
	B(int i):a(i){}
	virtual ~B(){}
	virtual void print()
	{
		cout<<"Class B - "<<a<<endl;
	}
private:
	int a;
};

class C:public A, public B
{
public:
	//基类A和B的构造函数都是带参的,所以子类需要对其初始化,顺序随意
	C(int i, int j, int k):A(i),B(j),a(k){}
	virtual ~C(){}
	virtual void print()
	{
		cout<<"Class C - "<<a<<endl;
	}
private:
	int a;
};

int main()
{
	C *c = new C(1,2,3);
	//如果多个基类中拥有相同的函数名,需要用::作用域标识符指出调用哪一个基类的函数,避免二义性
	c->A::print();
	c->B::print();
	c->print();
	//如果类A和类B都同时继承自类X,那么在创建类C的时候,类X的构造和析构函数会被执行两次,因为
	//类C在创建的时候,分别会去创建类A和类B,而类A和类B又会去创建类X,所以就类X会被创建销毁两次
	//如果类X中有函数Fun,那么类C在调用的时候需要指定调用哪个父类所继承的Fun函数
	c->A::Fun();
	//c->B::Fun();
	delete c;
	return 0;
}

再谈虚基类 前往以前的笔记

虚基类可以避免多重继承时函数调用的二义性,同理,也可以避免最上层的基类(这里指类X)被创建销毁两次

class X
{
public:
	X(){cout<<"X构造函数"<<endl;}
	virtual ~X(){cout<<"X析构函数"<<endl;}
	virtual void Fun()
	{
		cout<<"Class X"<<endl;
	}
};

//说明类X为虚基类
class A:virtual public X
{
public:
	A(int i):a(i){cout<<"A构造函数"<<endl;}
	virtual ~A(){cout<<"A析构函数"<<endl;}
private:
	int a;
};

class B:virtual public X
{
public:
	B(int i):a(i){cout<<"B构造函数"<<endl;}
	virtual ~B(){cout<<"B析构函数"<<endl;}
private:
	int a;
};

class C:public A, public B
{
public:
	//基类A和B的构造函数都是带参的,所以子类需要对其初始化,顺序随意
	//因为类X被限定只为子类产生一个实例,所以这里也可以对类X进行初始化
	C(int i, int j, int k):/*X(...),*/A(i),B(j),a(k){cout<<"C构造函数"<<endl;}
	virtual ~C(){cout<<"C析构函数"<<endl;}
private:
	int a;
};

int main()
{
	//类X只会被创建销毁一次,
	C *c = new C(1,2,3);
	//虚基类可以避免继承中的函数二义性
	c->Fun();
	delete c;
	return 0;
}

纯虚函数和抽象类

将一个虚函数初始化为0,这个函数就变成了纯虚函数,例如:

virtual int fun() = 0;

这种函数没有任何具体功能,不能直接调用它,有纯虚函数的类是抽象的,所以也不能实例化

一个类如果继承了抽象类,那么这个类就必须实现该抽象类中的方法

如果这个子类没有全部覆盖抽象基类的方法,那么这个子类也会变成一个抽象类

class X
{
public:
	virtual void print() = 0;
};
class A:public X
{
public:
	A(){}
	~A(){}
	//类A必须实现抽象类里面的纯虚函数
	void print(){cout<<"Class A"<<endl;}
	//或者继续把这个函数设为虚函数,那此时类A也属于抽象类
	//void print() = 0;
};
int main()
{
	A *pA = new A();
	pA->print();
	return 0;
}



<think>首先,用户的问题是:关于抽象类纯虚函数的描述中,错误的是( )。选项有A、B、C、D。 我需要分析每个选项的正确性: - **A. 纯虚函数的声明以“=0;”结束** 在C++中,纯虚函数确实以`= 0;`结尾。这是正确的。 - **B. 有纯虚函数的类叫抽象类,它不能用来定义对象** 抽象类不能实例化对象,这是标准定义。所以这也是正确的。 - **C. 抽象类的派生类如果不实现纯虚函数,它也是抽象类** 如果派生类没有覆盖所有纯虚函数,那么它仍然是抽象类。这正确。 - **D. 纯虚函数不能有函数体** 这是错误的。在C++中,纯虚函数可以有函数体。你可以为纯虚函数提供实现,但类仍然是抽象的,派生类必须覆盖它。纯虚函数可以有定义(函数体),但调用它通常通过派生类的覆盖函数。例如: ```cpp class Abstract { public: virtual void pureVirtual() = 0; // 声明为纯虚 }; void Abstract::pureVirtual() { // 可以提供实现 std::cout << "Pure virtual implementation\n"; } ``` 派生类可以调用这个实现,但必须覆盖它。所以选项D说“不能有函数体”是错误的。 因此,错误的描述是D。 现在,我需要回答这个问题,指出错误的是D,并解释为什么。 然后,在回答末尾,必须添加“§§相关问题§§”,并列出3-5个相关问题。问题必须基于用户的问题我的回答。 用户的问题是中文的,所以我需要用中文回答。 回顾之前的交互,用户提供了示例格式,我必须严格遵守:输出回答后,第一行是“§§相关问题§§”,然后列出问题,不要换行分散。 所以,结构是: - 回答部分:解释为什么D是错的。 - 然后,直接输出“§§相关问题§§” - 接着是1. 2. 3. 等问题列表。 相关问题需要基于抽象类纯虚函数,以及我的回答。 可能的相关问题: 1. 为什么纯虚函数可以有函数体?在什么场景下有用? 2. 抽象类接口有什么区别?在C++中如何实现纯接口? 3. 如果派生类只实现了部分纯虚函数,会发生什么? 4. 抽象类可以有非虚函数吗?对抽象性有什么影响? 5. 在多重继承中,抽象类纯虚函数如何处理? 确保3-5个问题。 最终输出: - 回答 - §§相关问题§§ - 1. ... - 2. ... - 3. ...</think>关于抽象类纯虚函数的描述中,错误的是**D**。具体分析如下: - **A. 正确**:C++纯虚函数必须通过`= 0;`语法声明(如`virtual void func() = 0;`)。 - **B. 正确**:包含至少一个纯虚函数的类是抽象类,禁止直接实例化对象(否则编译错误)。 - **C. 正确**:派生类若不覆盖(实现)基类所有纯虚函数,则其自身也成为抽象类,无法实例化。 - **D. 错误**:纯虚函数**可以有函数体**(即可提供实现)。例如: ```cpp class Abstract { public: virtual void pureFunc() = 0; // 声明为纯虚 }; // 为纯虚函数提供函数体(定义) void Abstract::pureFunc() { std::cout << "Pure virtual function body\n"; } ``` 派生类可通过`BaseClass::functionName()`调用基类实现,但必须覆盖该函数才能实例化。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

纯洁码农

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值