如何使继承的虚函数不可用?

How to make an inherited virtual function not usable?

我有一个抽象基础 class,它声明了一个纯虚函数 (virtual method() = 0;)。一些继承的 classes 专门研究并使用此方法,但有一个继承的 classes 我不想让此方法可用。我该怎么做?将其设为私有是唯一的选择吗?

Is making it private the only choice?

不,这根本不是一个选择,因为如果它是基础 classes 中的 publicprotected,您仍然可以访问该方法。

除了在 class 中实施该方法并求助于 运行 次失败之外,您无能为力。您 可以 将整个东西移植到模板并使用 静态多态性 ,进一步狡猾,您可以设计一个 编译时间 在某些情况下会失败,但这可能是设计矫枉过正。

我想你可以把它变成一个普通的虚函数,而不是像这样的纯虚函数:

virtual void method() { /* code */ } 

如果此函数未在另一个 class 中使用,您将能够捕捉到它。例如你可以警告自己:

virtual void method() { error = true; } //or whatever

好吧,你可以抛出它,这将使定位更容易。

void method() override { throw /* whatever */ ; } 

动态多态是一个运行时属性。因此出现运行时错误。如果你照顾一些会在编译时触发的东西,你需要静态多态性。

template<typename Child>
struct Parent {
    void callMe() {
        static_cast<Child*>(this)->callMeImpl();
    }
};

struct SomeChild : Parent<SomeChild> {

};

现在,如果您尝试从 SomeChild 扩展的父级调用 callMe,将出现编译时错误。

你也可以像动态多态一样持有指向父函数的指针,因为父函数会调用子函数

正如其他人所说,无法在编译时强制执行此操作。如果您指的是指向基 class 的指针,则编译器无法知道该指针是否指的是 派生的 classes 之一] 实施此方法或 .

的方法

所以这个案例必须在运行时处理。一种选择是只抛出异常。另一种选择是引入一个间接级别,这样您就可以在调用之前询问您的基 class 是否实现了某个功能。

假设您有一个 Base class 具有三种方法 foobardoit 并且一些派生的 class 没有想要实现 foo 那么你可以将 Base class 分成两个基础 classes:

class Base1 {
    public:
        virtual void foo() = 0;
};

class Base2 {
    public:
        virtual void bar() = 0;
        virtual void doit() = 0;
};

然后在您当前使用 Base 的地方改用 BaseSource:

class BaseSource {
    public:
        virtual Base1* getBase1() = 0;
        virtual Base2* getBase2() = 0;
};

其中 getBase1getBase2 可以 return nullptr 如果 BaseSource 不提供该接口:

class Derived : public BaseSource, public Base2 {
  public:   
     // don't implement foo();

     // Implemementation of Base2
     void bar() override;
     void doit() override;

     Base1* getBase1() override { return nullptr; } // Doesn't implement Base1
     Base2* getBase2() override { return this; }
};

int main() {
    std::vector<std::unique_ptr<BaseSource>> objects;
    objects.push_back(std::make_unique<Derived>());

    for (auto& o : objects) {
      auto b1 = o->getBase1();
      if (b1)
          b1->foo();
      auto b2 = o->getBase2();
      if (b2)
          b2->bar();
    }
}

Live demo.