virtual表

//在头文件中
#ifndef __CBASE_H__
#define __CBASE_H__

#include <iostream>
using std::cout;
using std::endl;
class CBase
{
public:
	virtual void f1()
	{
		cout<<"你妈妈喊你回家吃饭...."<<endl;
	}
	virtual void f2()
	{
		cout<<"神马都是浮云"<<endl;
	}
	virtual void f3()
	{
		cout<<"浮云回家吃饭了....."<<endl;
	}

};

#endif


//在主文件里
#include "stdafx.h"
#include "CBase.h"


int _tmain(int argc, _TCHAR* argv[])
{
	CBase d, *pd = &d;
	
	for (int i = 0; i < 3; ++i)
	((void (*)())(*((int*)(*((int*)pd))+i)))();
	return 0;
}


虚函数是动态函数的基础。

但是只能用于非静态非友元非内联的成员函数。(以上函数均没有this指针)

virtual只能用于说明类声明时的原型,实现时不能写。

具有继承性,基类中声明了虚函数,派生类中不论是否说明,同原型的函数自动为虚函数。

不是重载,而是重写。调用方式:通过基类类型的指针或者引用。执行时会根据指针指向对象的类型,决定调用哪个类的成员函数。一个指向基类的的指针,可以用来指向从基类中公有派生的任何对象,(注意必须是公有派生,兼容性原则)

virtual的作用就是使继承于基类的各派生类,肩负了重写虚函数的责任。

虚函数本身虽然不能是外来的友元函数,但可以外派出去,成为其他类的友元函数。

如果一个类中含有虚函数,则编译器对其生成的对象添加一个void型的指向指针的指针(它指向了一个指针数组<虚表>);

 

 

 

03-20
<think>好的,用户现在想了解C++中的virtual关键字。之前他们问过继承的相关内容,现在可能是在进一步深入学习多态和虚函数的概念。我需要先回顾之前提到的继承特点,尤其是虚函数的部分,然后详细解释virtual的作用。 首先,用户的问题是关于virtual的,所以我要明确它的用途。在之前的回答中,我提到了虚函数用于实现多态,以及基类析构函数应该声明为virtual。现在需要扩展这些内容,可能包括虚函数的工作原理、override关键字的使用,以及虚析构函数的重要性。 接下来,我需要考虑用户可能的背景。他们可能已经了解继承的基本概念,但对virtual的具体机制还不清楚。可能需要解释虚函数(vtable)和动态绑定的概念,但不宜过于深入底层,保持易懂。同时,用户可能想知道如何正确使用virtual,比如在哪些情况下必须使用,以及常见的错误有哪些。 另外,用户可能在实际编程中遇到了问题,比如对象切割或者内存泄漏,这些问题可以通过正确使用虚函数和虚析构函数来解决。因此,给出实际例子会很有帮助。例如,基类指针指向派生类对象时,如果没有虚析构函数,可能导致资源未正确释放。 还要注意用户之前提到的使用规范,比如override关键字和public继承,这些需要再次强调,以巩固他们的理解。可能还需要对比不使用virtual的情况,说明多态如何实现,以及虚函数与普通成员函数的区别。 需要检查是否有遗漏的关键点,比如纯虚函数和抽象类的概念,这也是virtual的一个重要应用。同时,提醒用户菱形继承问题虽然之前提到过,但virtual继承与虚函数是不同的概念,避免混淆。 最后,确保回答结构清晰,分点说明,结合代码示例,帮助用户逐步理解。避免使用过于专业的术语,但必要的术语需要解释清楚。总结部分要强调virtual的重要性,并给出使用建议,帮助他们避免常见错误。</think>C++ 虚机制深度解析(virtual 关键字的全面应用) 一、核心作用定位 virtual 是 C++ 实现运行时多态的核心关键字,主要应用于以下场景: 1. 虚函数(Virtual Functions):实现动态绑定 2. 虚析构函数(Virtual Destructors):确保正确的析构链 3. 纯虚函数(Pure Virtual Functions):创建抽象类 二、虚函数工作原理 1. 动态绑定机制 - 通过虚函数(vtable)实现 - 每个包含虚函数的类自动生成虚 - 对象内含隐藏的虚指针(vptr) 2. 内存结构示例: ```cpp class Base { public: virtual void func() { ... } }; // 内存布局: [vptr] -> [Base::func()地址] [其他成员变量] ``` 三、关键应用场景 1. 多态实现(经典示例): ```cpp class Animal { public: virtual void speak() { cout << "Animal sound" << endl; } }; class Dog : public Animal { public: void speak() override { cout << "Woof!" << endl; } }; void makeSound(Animal* a) { a->speak(); // 动态绑定到实际对象类型 } ``` 2. 必须使用虚函数的情况: - 通过基类指针/引用调用派生类方法 - 需要运行时类型识别(RTTI) - 实现接口继承 四、虚析构函数 1. 必要性验证实验: ```cpp class Base { public: ~Base() { cout << "Base dtor" << endl; } }; class Derived : public Base { public: ~Derived() { cout << "Derived dtor" << endl; } }; int main() { Base* ptr = new Derived(); delete ptr; // 仅调用Base析构函数! } ``` 2. 正确写法: ```cpp class Base { public: virtual ~Base() { ... } // 添加virtual }; ``` 五、纯虚函数与抽象类 1. 定义规范: ```cpp class Shape { public: virtual double area() = 0; // 纯虚函数 }; ``` - 含纯虚函数的类成为抽象类 - 不能直接实例化 - 强制派生类实现接口 六、现代 C++ 增强特性 1. override 标识符(C++11) ```cpp class Derived : public Base { public: void func() override { ... } // 明确示重写 }; ``` - 编译时检查重写正确性 - 提高代码可读性 2. final 标识符(C++11) ```cpp class Base { public: virtual void func() final { ... } // 禁止重写 }; ``` 七、性能考量 1. 虚函数调用成本: - 额外间接寻址(通过vptr访问vtable) - 通常多1次指针解引用操作 - 对比普通函数调用:约多10-20%开销 2. 优化建议: - 避免在性能关键路径过度使用 - 对简单函数考虑模板替代方案 - 合理使用final限制继承 八、高级应用模式 1. 虚函数协变(Covariant Return Types) ```cpp class Base { public: virtual Base* clone() { ... } }; class Derived : public Base { public: Derived* clone() override { ... } // 返回类型协变 }; ``` 2. 虚函数剖析(调试示例) ```cpp class Base { virtual void f1() {} virtual void f2() {} }; // 查看vtable内容: Base b; using FuncPtr = void(*)(); FuncPtr* vtable = *(FuncPtr**)&b; cout << "f1: " << vtable[0] << endl; // 输出函数地址 ``` 九、典型错误及防范 1. 切片问题(Object Slicing) ```cpp Derived d; Base b = d; // 派生类部分被"切片" b.vfunc(); // 调用Base版本 ``` 2. 构造/析构顺序陷阱 - 构造函数中调用虚函数:静态绑定 - 析构函数中调用虚函数:静态绑定 十、设计原则总结 1. 遵循 Liskov 替换原则 2. 基类析构函数必须为虚(当类被多态使用时) 3. 接口类建议使用纯虚函数 4. 合理控制继承层次深度 代码示例(完整虚函数体系): ```cpp #include <iostream> #include <memory> using namespace std; class Interface { public: virtual void execute() = 0; virtual ~Interface() = default; }; class Implementation : public Interface { public: void execute() override { cout << "Implementation executed" << endl; } }; int main() { unique_ptr<Interface> obj = make_unique<Implementation>(); obj->execute(); // 动态绑定到Implementation::execute() return 0; } ``` 关键要点总结: 1. virtual 实现运行时多态的核心机制 2. 虚函数调用成本可控,不应过度优化 3. 正确使用虚析构函数是资源管理的关键 4. override/final 增强代码安全性和可读性 5. 理解虚机制有助于深入掌握多态原理
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值