C++ 在具体类中强制重写方法

问题描述 投票:0回答:6

C++中有没有一种方法可以编写一个具体的类,当另一个类从它派生时,它有一个必须重写的方法。抽象类允许强制派生类创建任何抽象方法的具体版本,但我想要的是一个强制执行此操作但也可以单独使用的基类。我知道抽象方法也可以指定默认功能,但这仍然是一个无法实例化的抽象类。

我还查看了模板方法模式,但这似乎也不是我想要的。

c++ abstract-class
6个回答
4
投票

我假设您正在寻找编译时强制执行此条件的方法(感谢@Chad 指出这一点)

据我所知,C++ 中没有直接的语言机制。我的意思是,在方法声明前面没有保留关键字可以实现您的预期目标。

我认为你所说的是指向你的软件中的设计问题。假设您想强制 foo() 方法由以下代码片段中的所有继承类重新实现

class BaseButConcrete
{
    ... //Common stuff
    ... //

    virtual void foo()
    { /*implementation that you do not want to be inherited, but will be...*/ }
}

class DerivedOtherConcrete : public BaseButConcrete
{
    void foo()
    { /*different implementation, 
      but no obligation from compiler point of view*/ }
}

我看不出为什么所有常见的东西不能在抽象基类中移动,这没有什么好的设计原因。 根据您的描述,您不想继承 Derived 中的 foo 实现,因此不要继承该部分!因此,非常经典的设计应该能达到目的:

class AbstractBase
{
    ... //Common stuff has moved here
    ... //
    virtual void foo() =0;
}

class NotAnymoreBaseButStillConcrete : public AbstractBase
{
    void foo()
    { /*implementation that should not be inherited,
      and that will not by design*/ }
}

class DerivedOtherConcrete : public AbstractBase
{
    void foo()
    { /*different implementation, 
      now mandatory compiler-wise for the class to be concrete*/ }
}

这样,公共内容仍然在所有派生类之间共享,并且您可以将不想继承的内容(即 foo 实现)保留在不在同一继承路径上的类中。


1
投票

不,这是不可能的。如果要强制(在编译时)派生类定义虚函数,那么它的基类需要是抽象的,或者换句话说,基类需要有一个纯虚函数。抽象类(带有纯虚函数)不能是具体的,即你不能实例化它。


1
投票

一种选择是将类的所有实现放入一个抽象超类中,并从中继承。

  • 将具体类 T 的所有实现移至抽象类 S 中。
  • 在 S 中,使必须重写的方法成为纯虚函数——并提供它的定义。
  • T 子类 S.
  • 在T中,重写必须重写的函数,并调用S实现。
  • 不要子类化 T,而是子类化 S。
  • 防止 T 的子类化。

1
投票

我发现利用多重继承更加直观和干净,而不是定义中间类。如果我们的派生类也继承自一个抽象类,该抽象类声明了一个与我们想要强制重写的方法同名的纯虚方法,那么编译器将不允许实例化派生类型的对象,除非该方法实际上在派生类。

#include <iostream>

struct Base{
  virtual void print() {std::cout << "Base" << std::endl; }  
};

struct RequireOverride {
  virtual void print() = 0;   
};

struct D1: Base, RequireOverride {
  virtual void print() {std::cout << "D1" << std::endl; }  
};

struct D2: Base, RequireOverride {
  // no override of function print() results in a compilation error
  // when trying to instantiate D2
};


int main() {
  D1 d1;
  d1.print(); //ok


  //D2 d2; // ERROR: cannot declare variable 'd2' to be of abstract type 'D2'
           // because the following virtual functions are pure within 'D2':
           // virtual void RequireOverride::print()
  return 0;
}

如果您想强制多个方法存在重写,那么您可以将它们全部放入

RequireOverride
中,或者定义更多结构体进行多重继承,例如
RequireOverrideMethod1
RequireOverrideMethod2
,根据结合上下文。


1
投票

正如其他人提到的,您可以通过将当前的具体类拆分为抽象类和具体类来“修复”这一级别的派生。

该方法的常见概括是拥有一个必须用于从每个抽象类创建具体类的类模板。例如,它可以提供

clone
方法。或者,在微软的ATL中,它提供了
IUnknown
接口实现。

但是,具有自动生成的具体叶子的抽象类层次结构通常工作量太大且复杂。实际的方法是只记录必须覆盖的内容,例如

clone
。一般来说,你不能强迫别人的代码是正确的,你只能帮助它朝那个方向前进。

顺便说一句,如果你能更具体地说明你的具体问题,那么可能会有比这个一般性的愿望更好的答案。然而,通过概括你的问题,你概括了答案。


0
投票

使用 MSVC,您可以使用

= 0
强制覆盖方法,即使该方法有定义

这是 Microsoft 特定的,但考虑到用例仅用于检查代码,您可以定义一个宏以在其他编译器上忽略它。

MWE:

#include <iostream>

#ifdef _MSC_VER
#define MUST_OVERRIDE = 0
#else
#define MUST_OVERRIDE
#endif

class Base
{
public:
    virtual void Method() MUST_OVERRIDE
    {
        std::cout << "BASE";
    }
};

class Derived : public Base
{
public:
// Commenting out these lines leads generates a compile-time error
//    virtual void Method() override
//    {
//        Base::Method(); // we can still call the base method
//        std::cout << "DERIVED";
//    }
};

int main()
{
    Derived d;
    d.Method();
}
© www.soinside.com 2019 - 2024. All rights reserved.