【问题标题】:How to limit the accessibility of an abstract class to another abstract class and its subclasses?如何限制一个抽象类对另一个抽象类及其子类的可访问性?
【发布时间】:2020-01-19 12:04:00
【问题描述】:

给定两个抽象类 A 和 B,如何使 A 的公共成员函数只能被 B 及其派生类访问?即

class A {
public:
   virtual ~A(){}
   virtual void foo() = 0; // foo only accessible to B and its subclasses; foo is private to others
};
class B {
   virtual ~B(){}
   virtual void goo() = 0;
};

【问题讨论】:

  • 如果你想让它公开,你不能。公开意味着每个人都可以访问。
  • 您可以使用受保护的函数和继承或友元函数。
  • 使类B继承Aclass B : public A)然后我们将能够在B或其任何子类中定义foo。
  • 如果有人愿意,您可以使用#define private public#define class struct 禁用所有可访问性限制。

标签: c++ abstract-class access-modifiers


【解决方案1】:

这可能是过度设计,但这是我的建议。

TL;DR:将 goo() 设为 public,并为其添加一个只能由 B 或其派生类构造的虚拟参数。


首先,您创建一个只能由T 构造的虚拟类(比如说AccessKey<T>)(构造函数是私有的,Tfriend)。

此外,如果UT 的基数,AccessKey<T> 应该可以转换为AccessKey<U>

#include <cstddef>
#include <type_traits>

template <typename T>
class AccessKey
{
    friend T;
    template <typename> friend class AccessKey;

    constexpr AccessKey() {}

  public:
    template <typename U, std::enable_if_t<std::is_base_of_v<U, T>, std::nullptr_t> = nullptr>
    constexpr operator AccessKey<U>() const {return {};}
};

然后你将virtual void foo() = 0公开,并添加一个AccessKey&lt;B&gt;参数(前向声明class B首先)。

class A
{
  public:
    virtual void foo(AccessKey<B>) = 0;
};

那么……

class B
{
  public:
    void goo(A &a)
    {
        a.foo(AccessKey<B>{}); // ok
    }
};

class C : public B
{
  public:
    void goo(A &a)
    {
        a.foo(AccessKey<C>{}); // ok
    }
};

class D
{
  public:
    void goo(A &a)
    {
        a.foo(AccessKey<D>{}); // error: AccessKey<D> is not convertible to AccessKey<B>
        a.foo(AccessKey<B>{}); // error: AccessKey<B>() is private
    }
};

【讨论】:

    【解决方案2】:

    声明 A::foo 私有(或受保护)。如果是公开的,则访问没有限制。

    向不相关的类授予对非公共函数的访问权限的唯一方法是将该类声明为友元。

    但是,友善不是遗传的。所以,B 需要提供受保护的函数,委托给受限函数,以便派生类可以通过B 访问成员。

    一个例子:

    class A {
       ...
       friend class B;
    private:
       virtual void foo() = 0;
    };
    
    class B {
       ...
    protected:
        void foo(A& a) {
            a.foo();
        }
    };
    

    【讨论】:

    • 如果他们将其设为私有,则派生类无法使用该名称。
    • @NathanOliver AB 的派生类列为好友是不可行的。这就是派生类需要通过base中的helper来访问函数的原因。
    猜你喜欢
    • 1970-01-01
    • 2012-11-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多