10

似乎最好将虚拟方法设为私有,以便将以下两个客户端的接口分开 - 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;
}
4

3 回答 3

10

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

于 2013-02-03T08:45:52.783 回答
7

你完全正确:

  • 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会被调用,因为它的任何子项都不能覆盖它。

于 2013-02-03T14:37:37.153 回答
2

很难说出您在问什么,但是从示例中,您不需要使方法受到保护。它实际上可以是私有的。有关细节的详细信息,请参阅这篇文章:私有纯虚函数有什么意义?.

只要您不从派生类(或外部类)调用私有成员,就可以了。覆盖私人成员是可以的。您可以覆盖父母的私人信息确实听起来很顽皮和错误,但是在 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") {}

};
于 2013-02-03T08:53:03.883 回答