C++私有和受保护的虚拟方法

C++ private and protected virtual method

本文关键字:虚拟 方法 受保护 C++      更新时间:2023-10-16

似乎最好将虚拟方法设为私有,以便分离以下两个客户端的接口 -1. 实例化对象并调用该方法的客户端2. 派生自类并可能想要重写该方法的客户端。简单地说 - 第一个客户端不需要知道方法是否是虚拟的。他将基类称为公共非虚拟方法,而基类又将调用私有虚拟方法。例如,请参阅下面的代码。

现在,在虚拟方法需要对其基类的相应虚拟方法(例如 Save 方法)发送超级消息的情况下 - 它必须通过继承链中的所有虚拟方法才能保存对应于每个派生级别的数据 - 我们别无选择,只能使用受保护的虚拟方法 - 除非有一种方法可以保证在所有派生级别保存数据而不使用超级消息(我不知道)。

我想知道上述推理是否正确。

确保使用滚动来查看整个代码。

#include <iostream>
using namespace std;
class A {
    string data;    
protected:
    virtual void SaveData()= 0;
public:
    A():data("Data of A"){}
    void Save(){
        cout << data << endl;        
        SaveData();
    }
};
class B : public A {
    string data;
protected:
    virtual void SaveData() { cout << data << endl;}
public:
    B():data("Data of B") {}
};
class C : public B {
    string data;
protected:
    virtual void SaveData() {
        B::SaveData();
        cout << data << endl;
    }
public:
    C():data("Data of C") {}
};

int main(int argc, const char * argv[])
{
    C c;
    c.Save();
    return 0;
}

是的,如果您需要调用另一个类的 SaveData,则需要从该类访问它 - 所以publicprotected

你说得对:

  • NVI(非虚拟接口)要求不virtual方法public
  • 调用基类方法要求它不能private

因此,protected是显而易见的解决方案,至少在 C++03 年是这样。不幸的是,这意味着您必须信任派生类开发人员,不要忘记调用"super"。


在 C++11 中,您可以使用 final 来防止派生类重写 virtual 方法;这意味着您被迫引入一个新的钩子,例如:

class Base {
public:
    void save() {
        // do something
        this->saveImpl();
        // do something
    }
private:
    virtual void saveImpl() {}
};
class Child: public Base {
private:
     virtual void saveImpl() final {
         // do something
         this->saveImpl2();
         // do something
     }
     virtual void saveImpl2() {}
};

当然,每次都必须想出一个新名字的麻烦......但至少可以保证Child::saveImpl会被调用,因为它的子项都无法覆盖它。

很难说出你在问什么,但从示例中,你不需要保护该方法。 它实际上可以是私有的。 有关微妙之处的详细信息,请参阅这篇文章:私有纯虚拟函数的意义何在?

只要您不从派生类(或外部类)调用私有成员,就可以了。 覆盖私有成员是可以的。 你可以覆盖父母的隐私,这听起来确实很顽皮和错误,但在 c++ 中,你可以这样做。

以下应该没问题:

#include <iostream>
using namespace std;
class A {
    string data;    
private:
    virtual void SaveData()= 0;
public:
    A():data("Data of A"){}
    void Save(){
        cout << data << endl;        
        SaveData();
    }
};
class B : public A {
    string data;
private:
    virtual void SaveData() { cout << data << endl;}
public:
    B():data("Data of B") {}
};