【问题标题】:Restricting access to derived class for a pure virtual function in c++限制对 C++ 中纯虚函数的派生类的访问
【发布时间】:2013-09-23 13:16:12
【问题描述】:
class A
{    
public:
    void virtual magic() = 0;
    void bar()
    {
        magic();    // this should be legal
    }        
};

class B: public A
{    
public:
    void magic()
    {
        cout<<"implement magic here"<<endl;
    }
};

class C: public B
{
     void foo()
     {
         magic();     // this should not be allowed, i.e. create compile-time error
     }
};

因此,B 的纯虚拟基类 A 应有权访问 magic(),但不能访问 B 的任何派生类 C。这可以使用访问说明符和/或友元声明或以任何其他方式实现吗?

【问题讨论】:

  • 不清楚你在问什么。
  • @syam 我想通过 A 访问魔法,但同时 C 不应该能够访问魔法。

标签: c++ virtual


【解决方案1】:

基本上,您不能降低虚方法的可见性。一旦它在 A 中公开,就无法在任何派生类中使其成为受保护或私有的。

【讨论】:

  • +1;确实,没有整洁的方法。有一种邋遢的方式;和朋友。看我的回答。
  • @Bathsheba 您的回答与上述陈述并不矛盾,因为您的解决方案中的方法一开始是私有的。
【解决方案2】:

如果您可以访问class A,请将magic的访问权限更改为private

private:
         void virtual magic() = 0;

然后让B班成为A班的朋友:

class A
{
    friend class B;

【讨论】:

  • 你不需要让 B 成为 A 的朋友。你可以直接覆盖私有方法(或更改访问说明符)。见这里:ideone.com/HPkTIJ
  • 在这个解决方案中,magic()是否必须在BC的私有部分中实现?
【解决方案3】:

你真正想要的最有可能是separate the public interface from the implementation detail of inheritance,使用所谓的模板方法模式。

您的公共接口应该使用非虚拟方法。虚拟方法都应该是私有的。然后基类中的接口可以强制执行不变量并进行样板工作。派生类仍然可以覆盖虚拟方法,只是不能直接调用它。

只有在派生类需要调用虚方法的基实现时,才使虚方法受保护。差不多就这些了。

基类析构函数应该是公共的和虚拟的,或者是受保护的和非虚拟的。前者当您希望使用基类接口执行销毁时。 现在就这些了:)

具体来说:

#include <iostream>
#include <cassert>
using namespace std;

class A
{
    // we do magic without sprinking any dust, but optionally we could sprinkle some beforehand
    void virtual sprinkle() {};
    void virtual magic(int) = 0;
public:
    void doSomeMagic(int power) {
        assert(power > 3 and power < 8);
        sprinkle();
        magic(power);
    }
    virtual ~A() {}
};

class B: public A
{
    void magic(int power) {
        cout << "B: did magic of with power=" << power << endl;
    }

};

class C : public B
{
    void sprinkle() {
        cout << "C: also sprinked some dust before doing the magic" << endl;
    }
};

int main()
{
    B b;
    C c;
    b.doSomeMagic(5);
    c.doSomeMagic(6);
    return 0;
}
B: did magic of with power=5 
C: also sprinked some dust before doing the magic
B: did magic of with power=6

【讨论】:

  • 这有腿:可能优于我的回答。你能包括一些代码吗?
【解决方案4】:

正如 Dave S 的评论所建议的,更改 C::magic() 的访问说明符:

class A
{

    public:
         void virtual magic() = 0;
};

class B: public A
{

    public:
        void magic()
         {
           cout<<"implement magic here"<<endl;
         }
};

class C:public B
{
private:
    void virtual magic(){};
};

【讨论】:

  • C 不应该使用魔法。只有 A 才能获得 B 的魔法。
  • @Chris,我认为这是不可能的,因为从 A 派生的所有类都必须实现 magic()。你所能做的就是在 C 中隐藏这个方法。
猜你喜欢
  • 2018-10-14
  • 1970-01-01
  • 2018-01-25
  • 1970-01-01
  • 2018-05-02
  • 2017-01-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多