多态性和虚函数

1.什么是多态性?

多态性(c++中虚函数实现)是面向对象程序设计语言中数据抽象和继承之外的第三个基本特征。它是同一个事物在不同场景下的多种形态。例如c++中的可以定义同名函数实现不同的功能。
c++中多态分为静态多态和动态多态。静态多态是程序在编译期间就完成函数调用,例如函数重载和泛型编程;动态多态在程序执行期间判断所引用对象的实际类型,根据其实际类型调用相应的方法,例如虚函数。

2.虚函数

使用virtual关键字修饰类的成员函数时,指明该函数为虚函数,派生类需要重新实现,编译器将实现动态绑定。只在含有virtual函数的基类的地址时发生。当调用虚函数时,程序将动态的不同的对象。看代码:

class Fruitcolor
{
public:
    void AppleColor()
    {
        cout<<"Apple:read"<<endl;
    }
    void PearColor()
    {
        cout<<"Pear:yellow"<<endl;
    }

};

class Fruit
{
public:
    virtual void GetFruitColor(Fruitcolor &_fc)=0;//定义虚函数
};

class Apple:public Fruit
{
public:
    virtual void GetFruitColor(Fruitcolor &fc)
    {
        fc.AppleColor();
    }
};

class Pear:public Fruit
{
public:
    virtual void GetFruitColor(Fruitcolor &fc)
    {
        fc.PearColor();
    }
};

void FunTest()
{
    Fruit *p_apple,*p_pear;//
    p_apple = new Apple;
    p_pear = new Pear;
    Fruitcolor fc;

    p_apple->GetFruitColor(fc);//输出apple的color
    p_pear->GetFruitColor(fc);//输出pear的color

    delete p_apple;
    p_apple = NULL;
    delete p_pear;
    p_pear = NULL;
}

可以看到,Apple类和Pear类对Fruit类的GetFruitColor()虚函数进行了重写,在FunTest()函数里定义两个基类的指针p_apple和p_pear,使他们指向不同的派生类对象Apple和Pear,当不同的指针分别调用GetFruitColor()虚函数时,分别得到了苹果的颜色和梨的颜色。

注意:

  • 仅仅在声明时需要使用关键字virtual,定义时并不需要。
  • 如果一个函数在基类中被声明为virtual,那么在所有派生类中都是virtual的,不过建议在派生类标名virtual避免和其他函数混乱。
  • 在派生类中重新定义虚函数,要求函数名,函数类型,参数个数和类型完全与基类中的虚函数相同,根据自己的需求定义函数体。
  • 如果在派生类中没有对虚函数重新定义,则派生类简单的继承基类的虚函数。
  • 只能将类的成员函数声明为虚函数,不能将普通函数声明为虚函数。
  • 一个成员函数被声明为虚函数后,就不能再同一类族中再定义一个非virtual的但是与虚函数首部相同的函数。
  • 一般将析构函数声明为虚析构函数,即时基类不需要析构函数,也要显示的定义一个函数体为空放入虚析构函数,以保证在撤销对象动态分配空间时能得到正确的处理。
  • 只有成员函数和基可以是虚函数,构造函数,static修饰的成员函数,友元函数都不能为虚函数。

纯虚函数和抽象类

纯虚函数:
有时在类中将某一成员声明为虚函数,并不是因为基类本身的要求,而是因为派生类的需求,在基类中预留一个函数名,具体功能留给派生类区定义。这种情况下就可以将这个纯虚函数声明为纯虚函数。其一般形式是:
virtual 函数类型 函数名 (参数列表) =0;
注意:
纯虚函数没有函数体。最后的“=0”只是一种形式,告诉编译系统,它是一个纯虚函数,留在派生类中定义,并没有实际意义。纯虚函数只有在派生类中定义了之后才能被调用。如果在一个类中声明了纯虚函数,而在派生类中没有对该函数定义,则该虚函数在派生类中仍然为纯虚函数。
抽象类:
含有纯虚函数的类就成为抽象类。抽象类只是一种基本的数据类型,用户需要在这个基础上根据自己的需要定义处各种功能的派生类。抽象类的作用就是为一个类族提供一个公共接口。抽象类不能定义对象,但是可以定义指向抽象类的指针变量,通过这个指针变量可以实现多态。
例如上面代码中的Fruit类就是一个抽象类,Fruit类里面的函数是纯虚函数。

<think>好的,我现在需要处理用户关于C++多态性虚函数的问题。用户希望得到详细的解释使用方法。首先,我得回忆一下相关的知识点,并结合提供的引用内容来组织回答。 用户提供的引用内容提到了虚函数的作用、多态性的实现机制,以及虚函数的底层实现。引用[1][2]都强调了虚函数如何实现动态绑定,允许基类指针调用子类方法。引用[3]给出了一个代码示例,说明基类派生类中虚函数的重写以及函数重载的情况。这些内容都是回答用户问题的重要参考。 首先,我需要明确多态性的基本概念,分为编译时多态运行时多态。编译时多态包括函数重载模板,而运行时多态则通过虚函数继承实现。用户的问题重点在运行时多态,也就是虚函数的使用。 接下来,需要解释虚函数的定义方法,即使用virtual关键字,并在派生类中重写。同时,要提到如果派生类没有重写虚函数,则会继承基类的版本。这点在引用[2]中有提到,虚属性可以被继承。 然后,动态绑定的机制是关键。需要说明基类指针或引用如何指向派生类对象,并调用相应的虚函数。这部分可以结合引用[1]中的描述,用简单的例子来说明。例如,基类Animal派生类Dog,通过基类指针调用虚函数speak(),实际执行的是Dog类的实现。 另外,纯虚函数抽象类的概念也需要涵盖。用户可能需要了解如何定义接口,强制派生类实现特定方法。引用中没有直接提到纯虚函数,但这是多态性中的重要部分,需要补充。 虚析构函数的问题也不能忽视。如果基类的析构函数不是虚的,当通过基类指针删除派生类对象时,可能导致资源泄漏。引用中没有提到这一点,但这是使用虚函数时的常见注意事项,应该包含在回答中。 引用[3]中的代码示例展示了函数重载虚函数重写的区别。在派生类中,即使基类的函数是虚函数,重载的函数(如func(int))并不会自动成为虚函数,除非也使用virtual关键字声明。这可能是一个容易混淆的地方,需要解释清楚。 此外,虚函数的底层实现,如虚函数表(vtable)虚函数指针(vptr),可以简要提及,以帮助理解动态绑定的机制。这部分在引用[1]的末尾提到,可以适当展开。 用户可能还关心虚函数的使用场景注意事项,比如性能影响(虚函数调用有间接开销)、设计模式中的应用(如工厂模式、策略模式)等。这些内容可以增强回答的实用性。 最后,按照用户要求生成相关问题,需要围绕多态性虚函数的使用细节、设计考虑等方面提出,例如虚函数与普通成员函数的区别,虚函数表的工作原理,什么情况下必须使用虚函数等。 现在需要将以上思路组织成结构清晰的中文回答,确保符合格式要求:行内公式用$...$,独立公式用$$...$$,正确使用LaTeX语法,引用标识自然添加,并在最后生成相关问题。同时,回答需要分点说明,结合示例代码,帮助用户逐步理解。</think>### C++多态性虚函数详解 #### 一、多态性基础概念 多态性分为两种类型: 1. **编译时多态**:通过函数重载模板实现,例如: ```cpp int add(int a, int b) { return a+b; } double add(double a, double b) { return a+b; } ``` 2. **运行时多态**:通过虚函数继承实现,满足$Liskov$替换原则[^1] #### 二、虚函数核心机制 1. **定义方式** ```cpp class Animal { public: virtual void speak() { // 基类虚函数 cout << "Animal sound" << endl; } }; class Dog : public Animal { public: void speak() override { // 派生类重写 cout << "Woof!" << endl; } }; ``` 2. **动态绑定示例** ```cpp Animal* animal = new Dog(); animal->speak(); // 输出"Woof!" [^2] ``` 3. **虚函数表(vtable)** - 每个包含虚函数的类自动生成虚函数表 - 对象内部包含隐藏指针`vptr`指向vtable - 调用过程:`obj->vptr[n]()`(n为函数索引) #### 三、高级特性 1. **纯虚函数与抽象类** ```cpp class Shape { public: virtual double area() = 0; // 纯虚函数 }; ``` 2. **虚析构函数必要性** ```cpp class Base { public: virtual ~Base() {} // 必须声明为虚函数 }; ``` 3. **override/final关键字** ```cpp class Derived : public Base { public: void func() override {} // 显式声明重写 virtual void finalFunc() final {} }; ``` #### 四、关键应用场景 1. 插件架构设计 2. GUI事件处理系统 3. 游戏实体组件系统 4. 框架扩展点实现 ```cpp // 工厂模式示例 class Creator { public: virtual Product* create() = 0; }; class CarFactory : public Creator { public: Product* create() override { return new Car(); } }; ``` #### 五、性能与注意事项 1. 虚函数调用比普通函数多一次指针间接访问 2. 虚函数不应声明为`inline` 3. 构造函数中虚函数机制未生效 4. 虚函数表占用额外内存空间 $$ \text{内存开销} = \text{sizeof(vptr)} + \text{vtable大小} $$
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值