涉及虚函数的继承

#include "stdafx.h"
#include<iostream>
using namespace std;
class A{
public:
	void func() {
		cout << "A" << endl;
	}

};
class B :public A{
public:
	virtual void func() {
		cout << "B" << endl;
	}
};
class C :public B {
public:
	void func() {
		cout << "C" << endl;
	}
};
class D :public C {
private:
	void func() {
		cout << "D" << endl;
	}
};
int main()
{
	A a;
	B b;
	C c;
	A* ab = &b;
	A* ac = &c;
	B* bc = &c;
	C* cc = &c;
	a.func();
	b.func();
	c.func();
	ab->func();
	ac->func();
	bc->func();
	cc->func();
	D d;
	A* ad = &d;
	ad->func();
	B* bd = &d;
	bd->func();
	D* dd= &d;
	//dd->func();
    return 0;
}

从运行结果来看,前三个是ABC,这说明子类可以将父类的非虚函数改为虚函数,但是父类是虚函数那么子类一定是虚函数了

然后指针运行的结果是AACC,这点和Java的多态有些类似的情况,先看声明,再多态

然后结果是AC,最后注释掉的代码报错,这样看来即使子类将父类的public函数改为private了也可以用父类的指针来访问(觉得java在这点做的好一些)

<think>好的,我现在需要回答用户关于C++中父类含有虚函数时的继承机制及用法的问题。首先,我得回忆一下相关的知识点,并结合提供的引用内容来组织答案。 用户的问题涉及虚函数继承中的规则和实现细节,特别是虚函数表的处理。根据引用[1],当子类继承父类时,虚函数表会被继承,如果子类重写虚函数虚函数表中的相应条目会被更新为子类的函数地址。而如果子类不重写,虚函数表会保留父类的函数指针,如引用[2]所述。此外,引用[3]提到了析构函数设为虚函数的重要性,避免子类析构不被调用。引用[4]则讨论了多继承虚函数表的排列问题,子类的虚函数表添加在第一个父类的虚表之后。 接下来,我需要将这些信息结构化。首先解释虚函数的基本概念和作用,然后分点讨论继承时的规则,包括虚函数表的继承、覆盖、新增虚函数的情况,以及多继承的处理。同时需要提到析构函数设为虚函数的原因,以及不重写虚函数时的行为。 需要注意用户提到的格式要求:行内数学表达式用$...$,独立公式用$$...$$,但这个问题可能不太涉及数学公式,但如果有的话需要正确应用。例如,可以提到虚函数表的地址布局,或者函数指针的存储方式,不过可能不需要复杂的数学表达式。 然后,生成相关问题,这些问题应该围绕用户可能感兴趣的后续内容,比如如何验证虚函数表结构、多继承下的问题、虚析构函数的重要性等。需要确保问题相关且有深度,能够引导用户进一步学习。 最后,检查引用是否正确标注,每个引用标记应与提供的参考资料对应。例如,当讨论子类覆盖虚函数时,引用[1],当提到不重写时引用[2],析构函数相关引用[3],多继承引用[4]。 现在需要确保回答结构清晰,分点说明规则,举例说明,并引用正确。同时,避免使用Markdown格式,但用户给出的示例中使用了代码块,这里可能需要用中文描述代码示例,或者用文字说明,如代码部分用引号标出。 可能还需要指出虚函数表的创建和更新是由编译器自动处理的,子类不会复制父类的虚表,而是继承后修改,这一点在引用[1]中有详细说明。 总结回答的结构: 1. 虚函数的基本概念和作用 2. 继承规则: a. 虚函数表的继承 b. 覆盖虚函数时的更新 c. 新增虚函数 d. 多继承情况下的处理 3. 析构函数设为虚函数的重要性 4. 不重写虚函数的结果 5. 代码示例说明 6. 相关问题 需要确保每个部分都有对应的引用支持,并且语言简洁准确。例如,在讨论多继承时引用[4],说明虚函数表的位置安排。 现在开始组织这些内容,确保符合用户给出的格式要求,分点清晰,使用中文,并正确添加引用标记。</think>### C++父类含有虚函数时的继承机制及实现细节 在C++中,**虚函数**是实现运行时多态的核心机制。当父类包含虚函数时,子类继承的规则和实现细节如下: --- #### 1. **虚函数表(vtable)的继承与覆盖** - **虚函数表基础**:每个包含虚函数的类会生成一个虚函数表(存储指向虚函数的指针)。例如,父类`Base`的虚函数表包含其虚函数地址[^1]。 - **子类继承规则**: - 若子类**不重写父类虚函数**,则直接继承父类虚函数表中的函数地址。例如,子类`Derived`未重写时,调用虚函数会执行父类版本[^2]。 - 若子类**重写虚函数**,编译器会更新虚函数表中对应的条目,替换为子类函数的地址[^1]。 - **示例**: ```cpp class Base { public: virtual void func() { cout << "Base"; } }; class Derived : public Base { public: void func() override { cout << "Derived"; } // 虚函数表条目被更新 }; ``` --- #### 2. **新增虚函数虚函数表扩展** - 子类可以**新增虚函数**,此时虚函数表会在继承的父类虚表后追加新条目。 - **示例**: ```cpp class Derived : public Base { public: virtual void newFunc() {} // 新增虚函数虚函数表扩展 }; ``` --- #### 3. **多继承下的虚函数表** - 在多继承中,子类的虚函数表会按继承顺序排列。例如,继承`Base1`和`Base2`时,子类虚函数表会先包含`Base1`的虚表,再添加`Base2`的虚表,最后追加子类新增的虚函数[^4]。 - **覆盖不同父类的虚函数**时,每个父类虚表中对应的条目会被独立更新。 --- #### 4. **虚析构函数的重要性** - **规则**:若父类析构函数未声明为虚函数,当通过父类指针删除子类对象时,**子类析构函数不会被调用**,导致内存泄漏[^3]。 - **正确用法**: ```cpp class Base { public: virtual ~Base() {} // 必须声明为虚函数 }; ``` --- #### 5. **不重写虚函数的行为** - 若子类不重写父类虚函数,调用时直接使用父类实现。例如: ```cpp Derived d; Base* ptr = &d; ptr->func(); // 输出"Base"[^2] ``` --- #### 6. **验证虚函数表结构(调试技巧)** - 通过调试器内存窗口查看对象内存布局,虚函数表指针通常位于对象起始位置。 - 多继承下需注意虚函数表的合并与扩展问题[^4]。 --- ###
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值