【Effective C++】36绝不重新定义继承而来的non-virtual 函数

文章探讨了C++中非虚函数和虚函数在使用指针时的不同行为:非虚函数调用始终遵循静态绑定,而虚函数则根据实际对象类型进行动态绑定。通过示例展示了基类和派生类的mf方法调用差异。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

例子如下:

class B {
public:
	void mf();
};

class D : public B {};


D x;		// x是一个类型为D的对象
// 方式一
B* pB = &x  // 获得一个pB 指向 x
pB->mf();	// 经由指针调用mf

// 方式二
D* pD = &x	// 获得一个指针指向x
pD->mf();	// 经由指针调用mf

我们期望方式一和方式二调用mf 的表现是一致的。但是如果 D的实现如下

class D : public B {
public:
	void mf();		// 遮掩了B
};

此时方式一和方式二的表现形式就不一致了,造成这一行为的原因是: non-virtual 函数是 B::mf和D::mf都是静态绑定。意思是,由于pB是申明为指向B的指针,通过pB调用non-virtual函数永远是B所定义的版本,即时pB指向一个类型为B的派生类。

但是 virtual 函数却是动态绑定的。所以最后调用mf的时候都是调用了实际的类的哪个mf。
测试一下:

class B {
public:
    void mf()
    {
        std::cout << "B::mf()" << std::endl;
    }
};

class D : public B {
public:
    void mf()
    {
        std::cout << "D::mf()" << std::endl;
    }
};

int main()
{
    D d;
    std::cout << "call d.mf(): ";
    d.mf(); // D::mf()

    B* pb = &d;
    std::cout << "call pb->mf(): ";
    pb->mf(); // B::mf()

    D* pd = &d;
    std::cout << "call pd->mf(): ";
    pd->mf(); // D::mf()

    return 0;
}

输出:

call d.mf(): D::mf()
call pb->mf(): B::mf()
call pd->mf(): D::mf()
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值