C++虚函数的陷阱--派生类对象的基类函数调用基类虚函数出错

<span style="font-family: Arial, Helvetica, sans-serif; background-color: rgb(255, 255, 255);">最近写程序的时候发现,派生类对象的基类函数如果调用基类虚函数,则它将调用的是派生类的对应函数,而不是我想调用的基类的对应函数。</span>

下面用一个例子来说明:

//基类
class Base
{
public:
	void funA();
	virtual void funB();
protected:
private:
};

void Base::funA(){
	cout<<"这是Base类funA()"<<endl;
	funB();
}

void Base::funB(){
	cout<<"这是Base类funB()"<<endl;
}
//派生类
class Derivate :public Base
{
public:
	virtual void funB();
protected:
private:
};

void Derivate::funB(){
	cout<<"这是Derivate类funB()"<<endl;
}

我这里创建了一个基类Base和一个派生类Derivate,其中基类有一个函数funA()和一个虚函数funB()。派生类中,我重写函数funB()。

在Base::funA()中我调用了funB(),那么我想要调用的应该是Base::funB()。现在我们试写一下测试:

void main(){
	cout<<"1、调用派生类对象的funA():"<<endl;
	Derivate tmp;
	tmp.funA();
	cout<<"2、调用基类指针指向派生类对象的funA():"<<endl;
	Base* pBase;
	pBase = &tmp;
	pBase->funA();
}

运行结果是:

实际如果我是用派生类对象来调用funA(),那么他将调用Derivate::funB(),而不是Base::funB(),和基类指针指向派生类对象时,运行fun()的结果相同。

解决方法:那么既想要保持funB()函数的多态性,又想在基类能准确调用基类函数Base::funB()应该怎么做呢?那就加上类限定符:

void Base::funA(){
	cout<<"这是Base类funA()"<<endl;
	Base::funB();
}

所以,基类函数调用某虚函数时,要注意加上类限定符。

全部测试代码:

#include <iostream>
using namespace std;
//基类
class Base
{
public:
	void funA();
	virtual void funB();
protected:
private:
};

void Base::funA(){
	cout<<"这是Base类funA()"<<endl;
	funB();
}

void Base::funB(){
	cout<<"这是Base类funB()"<<endl;
}
//派生类
class Derivate :public Base
{
public:
	virtual void funB();
protected:
private:
};

void Derivate::funB(){
	cout<<"这是Derivate类funB()"<<endl;
}

void main(){
	cout<<"1、调用派生类对象的funA():"<<endl;
	Derivate tmp;
	tmp.funA();
	cout<<"2、调用基类指针指向派生类对象的funA():"<<endl;
	Base* pBase;
	pBase = &tmp;
	pBase->funA();
}
时间: 2024-10-13 19:05:58

C++虚函数的陷阱--派生类对象的基类函数调用基类虚函数出错的相关文章

面向对象--多继承&amp;派生类对象内存布局分析&amp;各基类指针所指向的位置分析

背景 原文链接:ordeder  http://blog.csdn.net/ordeder/article/details/25477363 关于非虚函数的成员函数的调用机制,可以参考: http://blog.csdn.net/yuanyirui/article/details/4594805 成员函数的调用涉及到面向对象语言的反射机制. 虚函数表机制可以查看下面这个blog: http://blog.csdn.net/haoel/article/details/1948051 总结为: 其一

定义一个复数(z=x+iy)类Complex,包含: 两个属性:实部x和虚部y 默认构造函数 Complex(),设置x=0,y=0 构造函数:Complex(int i,int j) 显示复数的方法:showComp()将其显示为如: 5+8i或5-8i 的形式。 求两个复数的和的方法:(参数是两个复数类对象,返回值是复数类对象)public Complex addComp(Compl

因标题框有限,题目未显示完整,以下再放一份: 定义一个复数(z=x+iy)类Complex,包含: 两个属性:实部x和虚部y 默认构造函数 Complex(),设置x=0,y=0 构造函数:Complex(int i,int j) 显示复数的方法:showComp()将其显示为如: 5+8i或5-8i 的形式. 求两个复数的和的方法:(参数是两个复数类对象,返回值是复数类对象)public Complex addComp(Complex C1,Complex C2) 求两个复数的差的方法:(参数

C++ 基类、派生类对象指针的声明与使用

1.类指针.对象指针 class x{ //- public: voidshow(); }; main() { x x1,*ptr1;           //定义类x的对象x1和类x的指针ptr1 x x2,*ptr2;           //定义类x的对象x2和类x的指针ptr2 x*ptr3;                 //定义类x的指针ptr3 //- ptr1 =&x1;           //将指针ptr1指向x1对象 ptr2 =&x2;           //将

为什么基类指针和引用可以指向派生类对象,但是反过来不行?

为什么基类指针和引用可以指向派生类对象,但是反过来不行? 基类指针和引用 BaseClass *pbase = NULL; DerivedClass dclass; pbase = & dclass; 基类指针和引用可以指向派生类对象,但是无法使用不存在于基类只存在于派生类的元素.(所以我们需要虚函数和纯虚函数) 原因是这样的: 在内存中,一个基类类型的指针是覆盖N个单位长度的内存空间. 当其指向派生类的时候,由于派生类元素在内存中堆放是:前N个是基类的元素,N之后的是派生类的元素. 于是基类的

C++:基类与派生类对象之间的赋值兼容关系

4.5 基类与派生类对象之间的赋值兼容关系 在一定条件下,不同类型的数据之间可以进行类型转换,例如可以将整型数据赋给双精度型变量. 在赋值之前,先把整型数据转换为双精度型数据,然后再把它双精度型变量.这种不同类型之间的自动转换,称为赋值兼容.在基类和派生类对象之间也存在有赋值兼容关系,基类和派生类对象之间的赋值兼容规则是指在需要基类对象的任何地方,都可以使用公有派生类的对象来代替.因为,通过公有继承,除了构造函数和析构函数外,派生类保留了基类其他的所有的成员.那么,派生类就具有基类的全部功能,凡

C++基类指针指向的派生类对象内存的释放

C++由于基类指针可以指向不同的派生类对象,因此当赋予基类指针不同的地址时,要注意之前的派生类对象的内存释放. int main(){ Parent* ptr = new Child1; Child2 myChild2; Child3 myChild3; ptr->show(); delete ptr; //位置1 ptr = &myChild2; ptr->show(); delete ptr; //位置2 ptr = &myChild3; ptr->show(); d

C++ Primer 学习笔记_22_类与数据抽象(8)--static 成员变量、static 成员函数、类/对象的大小

一.static 每个static数据成员是与类关联的对象,并不与该类的对象相关联!非static数据成员存在于类类型的每个对象中,static数据成员独立该类的任意对象存在. static成员函数没有this形参,它可以直接访问所属类的static成员,但是不能直接使用static成员! 1.static 成员变量 对于特定类型的全体对象而言,有时候可能需要访问一个全局的变量.比如说统计某种类型对象已创建的数量. 如果我们用全局变量会破坏数据的封装,一般的用户代码都可以修改这个全局变量,这时可

Objective-C对象之类对象和元类对象

作者:wangzz 原文地址:http://blog.csdn.net/wzzvictory/article/details/8592492 转载请注明出处 如果觉得文章对你有所帮助,请通过留言或关注微信公众帐号wangzzstrive来支持我,谢谢! 作为C语言的超集,面向对象成为Objective-C与C语言的最大区别,因此,对象是Objective-C中最重要的部分之一.目前面向对象的语言有很多,Objective-C中的对象又和其他语言中的对象有什么区别呢?下面来简单介绍Objectiv

如何让类对象只在栈(堆)上分配空间?(转)

转自:http://blog.csdn.net/hxz_qlh/article/details/13135433 在C++中,类的对象建立分为两种,一种是静态建立,如A a:另一种是动态建立,如A* ptr=new A:这两种方式是有区别的. 1.静态建立类对象:是由编译器为对象在栈空间中分配内存,是通过直接移动栈顶指针,挪出适当的空间,然后在这片内存空间上调用构造函数 形成一个栈对象.使用这种方法,直接调用类的构造函数. 2.动态建立类对象,是使用new运算符将对象建立在堆空间中.这个过程分为