不要重新定义继承的非虚函数
如果基类和派生类有相同的非虚函数,会有什么情况发生?
看下面的例子:
class B {
public:
void mf();
};
void B::mf()
{
cout << "Call B::mf() Function !" << endl;
}
class D: public B { ... };
int main()
{
D x; // x是类型D的一个对象
B *pB = &x; // 得到x的指针
pB->mf(); // 通过指针调用mf
D *pD = &x; // 得到x的指针
pD->mf();
return 0;
}
输出结果:
Call B::mf() Function !
Call B::mf() Function !
这两种情况调用的mf()都是B.mf(),因为类D并没有重新定义自己的mf()函数,而是继承的B的函数。
但是若D这样定义:
class D: public B {
public:
void mf(); // 隐藏了B::mf; 参见条款50
};
输出结果:
Call B::mf() Function !
Call D::mf() Function !
那么pB->mf(); 调用的是B::mf(),而pD->mf();调用的则是D::mf()。
行为的两面性产生的原因在于,B::mf和D::mf非虚函数是静态绑定,因为pB被声明为指向B的指针类型,通过pB调用非虚函数时将总是调用那些定义在类B中的函数 ---- 即使pB指向的是从B派生的类的对象,如上例所示。
相反,虚函数是动态绑定的,因而不会产生这类问题。如果mf是虚函数,通过pB或pD调用mf时都将导致调用D::mf,因为pB和pD实际上指向的都是类型D的对象。
mf()是虚函数的情况:
#include <iostream>
using namespace std;
class B {
public:
virtual void mf();
};
void B::mf()
{
cout << "Call B::mf() Function !" << endl;
}
class D: public B
{
public :
void mf();
};
void D::mf()
{
cout << "Call D::mf() Function!"<< endl;
}
int main()
{
D x; // x是类型D的一个对象
B *pB = &x; // 得到x的指针
pB->mf(); // 通过指针调用mf
D *pD = &x; // 得到x的指针
pD->mf();
return 0;
}
输出:
Call D::mf() Function!
Call D::mf() Function!
分享到:
相关推荐
- 当一个类继承自另一个含有虚函数的基类时,派生类会拥有自己的虚函数表,并且该表通常会包含基类虚函数表中的函数地址,以及派生类自身定义的虚函数地址。 2. **虚表指针的初始化:** - 每个对象都会有一个虚表...
### C++中析构函数定义成虚函数的原因 在C++编程中,为了实现多态性,虚函数机制被广泛采用。然而,在某些特定场景下,尤其是涉及到派生类和基类之间的对象管理时,将析构函数声明为虚函数显得尤为重要。本文将深入...
在继承层次中,派生类的虚函数表可能包含来自基类的虚函数以及自身定义的虚函数。当派生类重写(override)基类的虚函数时,虚函数表中的对应条目会被更新,指向派生类中新的函数实现。 #### 结论 虚函数表是C++中...
在编程世界中,继承、虚函数和抽象类是面向对象编程(OOP)中的核心概念。这三者共同构建了类的层次结构,使得代码更加模块化,易于维护和扩展。接下来,我们将深入探讨这三个概念及其相关用法。 首先,**继承**是...
- C++的虚函数在C#中对应为接口(Interface)或抽象类(Abstract Class)。 - C++的模板函数无法直接转换,可能需要创建多个C#方法来模拟。 4. **DLL互操作**: - 提供的文件中有`.dll`文件(如:sigimplib.dll...
在“C++继承多接口,调用虚函数跳转到错误接口的虚函数的奇怪问题demo”中,我们可以假设存在以下情况: ```cpp class InterfaceA { public: virtual void foo() = 0; }; class InterfaceB { public: virtual ...
2. **多态性实现**:当一个类继承自包含虚函数的基类时,子类可以重新定义(重写)该虚函数,这样就实现了运行时的多态性。 3. **虚函数表**:为了支持虚函数的动态绑定,C++编译器会在每个含有虚函数的对象中添加一...
在C++中,虚函数是实现多态性的重要...理解和利用虚函数表可以帮助我们更深入地理解C++的多态机制和内存布局,但在实际编程中,我们通常使用C++的语法特性,如基类指针调用虚函数,来实现多态,而非直接操作虚函数表。
2. 派生类定义:继承自基类,并可能重写基类的虚函数,如: ```cpp class Derived : public Base { public: void func1() override { /*...*/ } void func2() { /*...*/ } void func3() { /*...*/ } // 非虚函数 ...
在C++编程语言中,多态性和虚函数是面向对象编程的重要特性,它们允许程序员创建灵活且可扩展的代码结构。本次实验旨在深入理解和熟练运用这两个概念。实验报告的标题和描述表明,这是一个关于C++实验,特别是针对多...
虚函数调用相比非虚函数会稍慢,因为需要在运行时查找虚函数表。但在大多数情况下,这种性能差异可以忽略不计。 通过理解并熟练应用这些技巧,可以充分利用C++的多态性,编写出更加灵活和可扩展的代码。虚函数是...
每当我们定义一个含有虚函数的类,编译器会自动生成一个虚函数表,其中包含了类中所有虚函数的地址。每个对象在其内存布局中会包含一个虚指针,这个指针在对象创建时被初始化为指向相应的虚函数表。 虚函数调用的...
如果类继承自其他类并重写了某个虚函数,那么子类的虚函数表将会包含新的函数指针,而父类的虚函数表仍然保留旧的函数指针。这样,当通过基类指针调用虚函数时,实际调用的是子类的版本,这就是动态绑定或多态性。 ...
在C++编程语言中,虚函数(Virtual Functions)和多态(Polymorphism)是面向对象编程的重要特性,它们使得程序具有高度的灵活性和可扩展性。本文将深入探讨这两个概念,结合示例代码进行详细解释。 首先,我们来...
C++的纯虚函数则是通过在虚函数声明后加`=0`来定义的,例如`virtual void showmember() = 0;`。纯虚函数没有函数体,声明含有纯虚函数的类为抽象类,抽象类不能被实例化,只能作为其他类的基类。抽象类的目的是为了...
C++虚函数是面向对象编程中的一个重要特性,它允许我们实现多态性,即一个基类指针或引用可以调用派生类重写的成员函数。这种能力在编写可扩展和可复用的代码时非常关键。下面我们将深入探讨C++虚函数的应用及其实现...
### C++ 中的继承、多态、虚函数与纯虚函数 #### 继承 **概念解析** 在面向对象编程语言如 C++ 中,继承是一种让一个类(派生类)能够继承另一个类(基类)特性的机制。这种机制不仅能够重用代码,还能在原有基础...