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

时间:2013-02-03 08:12:11

标签: c++

似乎最好将虚方法设为私有,以便分离用于跟踪两个客户端的接口 - 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;
}

3 个答案:

答案 0 :(得分:9)

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

答案 1 :(得分:5)

你是对的:

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

因此protected是显而易见的解决方案,至少在C ++ 03中是这样。不幸的是,这意味着您必须相信派生类开发人员不要忘记称为“超级”。


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

答案 2 :(得分:2)

很难说出你在问什么,但是从这个例子中,你不需要保护方法。它实际上可以是私人的。有关细微之处的详细信息,请参阅此帖:What is the point of a private pure virtual function?

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

};