简体   繁体   English

在c ++中限制对纯虚函数的派生类的访问

[英]Restricting access to derived class for a pure virtual function in c++

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
     }
};

Thus the pure virtual base class A of B shall have access to magic() , but not any derived class C of B . 因此, B的纯虚基类A应该可以访问magic() ,但不能访问任何B派生类C Can this be achieved using access specifiers and/or friend declarations or in any other way? 这可以使用访问说明符和/或朋友声明或以任何其他方式实现吗?

Basically, you cannot reduce the visibility of a virtual method. 基本上,您无法降低虚拟方法的可见性。 Once it's public in A , there's no tidy way to make it protected or private in any of the derived classes. 一旦它在A公开,就没有任何整洁的方法可以使它在任何派生类中受到保护或私有。

If you have access to class A , change the access of magic to private : 如果您有权访问class A ,请将magic访问权限更改为private

private:
         void virtual magic() = 0;

Then make class B a friend of class A: 然后让B班成为A班的朋友:

class A
{
    friend class B;

What you really want is most likely to separate the public interface from the implementation detail of inheritance , using so-called Template Method pattern. 您真正想要的是使用所谓的模板方法模式,最有可能将公共接口与继承的实现细节分开

Your public interface should use non-virtual methods. 您的公共接口应使用非虚方法。 The virtual methods should all be private. 虚拟方法应该都是私有的。 Then the interface in the base class can enforce invariants and do boilerplate work. 然后基类中的接口可以强制执行不变量并进行样板工作。 The derived classes can still override the virtual method , they just can't call it directly. 派生类仍然可以覆盖虚方法 ,它们不能直接调用它。

Only if the derived classes need to invoke the base implementation of a virtual method, make the virtual method protected. 仅当派生类需要调用虚方法的基本实现时,才能使虚方法受到保护。 That's almost all. 这几乎都是。

The base class destructor should be either public and virtual, or protected and nonvirtual. 基类析构函数应该是公共的和虚拟的,或者是受保护的和非虚拟的。 The former when you wish to perform destruction using the base class interface. 前者当您希望使用基类接口执行销毁时。 Now that's really all :) 现在 ,这真的全部:)

Concretely: 具体来说:

#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

As Dave S's comment suggests, change the access specifier of C::magic(): 正如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(){};
};

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM