C++中使用多态的注意事项——如何调用基类被重载过的虚函数

       在C++中,实现多态的方式就是继承基类,不同的派生类重写相同函数名,不同函数内容的虚函数。下面就是一个非常简单的多态的示例:

class Father {
public:
	virtual void func() {
		std::cout << "Father's func()" << std::endl;
	}
};

class Son : public Father {
public:
	void func() override {
		std::cout << "Son's func()" << std::endl;
	}
};

int main()
{
	Father *p = new Son();

    p->func();
	// 调用 Father 类的 func() 函数
	p->Father::func();

	delete p;
	return 0;
}

       我们可以很明显的知道这里的 p->func()得到的结果是“Son's func()”。至于为什么是“Son's func()”,以及底层涉及到的虚函数、虚函数表原理,可以取看看这篇博客,博主讲的非常详细。我也受益良多。

C++虚函数表,虚表指针,内存分布__silverBlack的博客-优快云博客

       这时候我就会想,父对象指针能够指向子对象的内存空间,调用子对象的公开成员,那么父对象还能不能调用父类本身的虚函数呢。于是就想到用作用域修饰。p->Father::func()就成功打印了“Father's func()”。

       此时又会有一个问题,那就是func是public修饰的,很多时候我们写的成员函数,是用protected、private修饰的。于是我将代码改进,改成以下写法,更贴合实际开发。

class Father {
public:
	void runFunc() {
		func();
	}
	protected:
	virtual void func() {
		std::cout << "Father's func()" << std::endl;
	}
};

class Son : public Father {
public:
	void runFunc(){
		func();
	}
protected:
	void func() override {
		std::cout << "Son's func()" << std::endl;
	}
};

int main()
{
	Father *p = new Son();

    p->runFunc();
	// 调用 Father 类的 func() 函数
	p->Father::runFunc();

	delete p;
	return 0;
}

现在我们会发现,无论是 p->runFunc()还是p->Father::runFunc(),最后打印的都是"Son's Func()"。

很奇怪吧。即使加了作用域,还是没办法输出"Father's Func()"。

后来我从虚函数的多继承原理中受到了启发。当派生类继承多个基类,且每个基类中都有各自的虚函数时,派生类和基类共用的虚函数表中,无论声明的时候函数的顺序是怎么样的,最先继承的基类的虚函数都会被放在虚函数表的最上方,然后是第二个基类的虚函数,依此类推。

所以我猜想,在Father类中的runFunc函数中调用的func函数,编译器会优先在虚函数表中从头开始寻找func函数。导致这种现象的发生。

为了避免出现这种情况,在写代码的时候要细心一些,及时的在虚函数调用前加上作用域,如下图:

class Father {
public:
	void runFunc() {
		Father::func();
	}
protected:
	virtual void func() {
		std::cout << "Father's func()" << std::endl;
	}
};

这样写,就可以通过调用Father::runFunc来调用父类的虚函数了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值