private 属性的虚函数

问题描述

近日看代码时发现标准库里面有一个带 private 的纯虚函数,感到十分困惑,基类的 private 成员派生类无法访问,为什么要声明 private 的纯虚函数。

  class memory_resource
  {
    static constexpr size_t _S_max_align = alignof(max_align_t);

  public:
    memory_resource() = default;
    memory_resource(const memory_resource&) = default;
    virtual ~memory_resource(); // key function

    memory_resource& operator=(const memory_resource&) = default;

    [[nodiscard]]
    void*
    allocate(size_t __bytes, size_t __alignment = _S_max_align)
    __attribute__((__returns_nonnull__,__alloc_size__(2),__alloc_align__(3)))
    { return do_allocate(__bytes, __alignment); }

    void
    deallocate(void* __p, size_t __bytes, size_t __alignment = _S_max_align)
    __attribute__((__nonnull__))
    { return do_deallocate(__p, __bytes, __alignment); }

    bool
    is_equal(const memory_resource& __other) const noexcept
    { return do_is_equal(__other); }

  private:
    virtual void*
    do_allocate(size_t __bytes, size_t __alignment) = 0;

    virtual void
    do_deallocate(void* __p, size_t __bytes, size_t __alignment) = 0;

    virtual bool
    do_is_equal(const memory_resource& __other) const noexcept = 0;
  };

参考资料 1:C++ 为什么会有 private virtual 函数,这样写好吗? - V2EX

用 private 还是 protected 完全取决于你自己的需要啊,这一点是不要纠结的。

基类中标记为 private 的纯虚函数是没有实现的,你要继承这样的基类就必须自己实现一个与纯虚函数同名的函数。也就是实际上可以理解为是派生类内部独立声明的一个有 private (或者其他属性)的函数,只是与基类中要求的同名而已。所以无论是哪种属性派生类中纯虚函数的实现是可以被派生类自己访问的。

这两者 private 还是 protected 只在多继承中会产生区别
按照你的示例代码举个例子:
GameCharacter 派生出一个类 RPGGameCharacter。
RPGGameCharacter 这个类的成员函数可以自由的使用 doHealthValue()
RPGGameCharacter 又派生出一个 MMORPGGameCharacter。
MMORPGGameCharacter 这个类的成员函数则不能使用 doHealthValue,因为 doHealthValue 是 private 的,如果声明的时候标记为 protected 那么就可以。

参考资料 2:c++ - What is the point of a private pure virtual function? - Stack Overflow

测试

/*********************************************************************************
 * @copyright Copyright (c) 2024
 *
 * @author W Wu (ww1820@qq.com)
 * @version 0.1
 * @date 2024-03-29
 *
 * @file private_virtual.cpp
 * @brief private 属性的虚函数的作用
 ********************************************************************************/
#include <iostream>
class Base
{
public:
    virtual ~Base() = default;
    void test1()
    {
        func1();
        func2();
        func3();
    }

    virtual void test() = 0;

protected:
    virtual void func1() = 0;

private:
    virtual void func2() = 0;
    virtual void func3() { std::cout << "Base::func3" << std::endl; }
};

class Derived : public Base
{
public:
    virtual void test() override
    {
        func1();
        func2();
        // Derived 未实现,不可见
        // func3();
    }

protected:
    virtual void func1() override { std::cout << "Derived::func1" << std::endl; }

private:
    virtual void func2() override { std::cout << "Derived::func2" << std::endl; }
};

class DDerived : public Derived
{
public:
    virtual void test() override
    {
        func1();
        // DDerived 未实现,不可见
        // func2();
        // func3();
    }

protected:
    virtual void func1() override { std::cout << "DDerived::func1" << std::endl; }
};

int main(int argc, char const* argv[])
{
    /* code */
    Base* ptrD = new Derived();
    std::cout << "=== ptrD->test1(): " << std::endl;
    ptrD->test1();

    std::cout << "=== ptrD->test(): " << std::endl;
    ptrD->test();

    Base* ptrDD = new DDerived();

    std::cout << "=== ptrDD->test1(): " << std::endl;
    ptrDD->test1();

    std::cout << "=== ptrDD->test(): " << std::endl;
    ptrDD->test();

    delete ptrD;
    ptrD = nullptr;
    delete ptrDD;
    ptrDD = nullptr;

    return 0;
}

输出:

image.png

总结

虚函数(不管是不是纯虚函数)的声明为 private 是为了阻止派生类访问基类的实现,而派生类可以有自己的实现。虚函数不管访问性是 public、protected 还是 private,都能实现多态,受影响的只有外部可见性。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

AWei_i_i

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值