在 C++ 中可以有一个虚拟类型吗?

Posted

技术标签:

【中文标题】在 C++ 中可以有一个虚拟类型吗?【英文标题】:Is it possible to have a virtual type in C++? 【发布时间】:2020-01-14 21:39:03 【问题描述】:

我有一个类MyClass(带有几个虚函数),它对一个名为MyType 的对象执行操作。

MyClassImpl类继承MyClass并实现了虚函数,但是我需要给MyType添加额外的成员,但是我不想修改类MyType(而是我想保留它通用)。

现在,如果我创建一个MyTypeImpl 并继承MyType,我可以添加成员。但是,如何使MyClassImpl(继承自MyClass)中的非虚函数使用新的MyTypeImpl

我能想到的唯一方法是让MyClass 使用MyTypeImpl,但我想避免在泛型类中使用实现,因为我可能会使用各种不同的实现。

下面是一个简单的类可能是什么样子的例子。当然,代码不会编译,因为MyTypeImpl而不是MyType中添加的方法和成员。

class MyType 
  public:
    void increment() 
      data_++;
    
  protected:
    int data_ = 0;
;

class MyClass 
  public:   
    void alg() 
      sub_routine_1();
      sub_routine_2();
      modify_mytype();
    ;

  protected:
    MyType mytype_;

    virtual void sub_routine_1() = 0;
    virtual void sub_routine_2() = 0;

    void modify_mytype() 
      mytype_.increment();
    ;
;

class MyTypeImpl : public MyType 
  public:
    void decrement() 
      data_--;
      is_decremented = true;
    ;

  protected:
    bool is_decremented = false;;
;

class MyClassImpl : public MyClass
  public:
    void print() 
      mytype_.print();
    ;
  protected:
    virtual void sub_routine_1() 
      //do algorithm things here
      mytype_.increment();
      mytype_.increment();
    ;
    virtual void sub_routine_2() 
      //do more algorithm things here
      mytype_.decrement();
      mytype_.decrement();
    ;
;

【问题讨论】:

您能否提供一个用例或您编写的一些代码示例来尝试完成此操作?我认为这有助于使您的问题更清楚 如果您不能/不想在 MyType 级别提供通用接口(例如,以纯或空实现的虚函数的形式),那么您必须测试和/或动态转换为 MyTypeImpl ind MyClassImpl。 您能edit your question 并添加一个代码示例来说明您正在尝试做什么吗?即使你不能完全做到这一点,一个具体的例子也会帮助我们更好地理解你。 听起来你想要一些东西visitor-ish. 我将做一个简单的例子并添加到描述中。 【参考方案1】:

看到您的示例后,我现在看到您只想扩展该类的功能而不修改原始类。如果您需要添加其他功能,但您不想更改存储在 MyClass 中的类型,那么我没有任何方法可以做到这一点,除非至少修改 MyType 以包含虚拟功能您要调用的函数。

您还需要使 MyClass 获取指向 MyType 的指针,以便您可以使用多态性并使调用解析为正确的实现:

动态多态性解决方案:

#include <iostream>

class MyType 
  public:
    virtual void increment() 
      data_++;
    

    // To be implemented by implementation class
    virtual void print() = 0;

    // To be implemented by implementation class
    virtual void decrement() = 0;

  protected:
    int data_ = 0;
;

class MyTypeImpl : public MyType

public:
    void print() 
        std::cout << 42 << std::endl;
    

    void decrement() 
        data_--;
        is_decremented = true;
    ;

protected:
    bool is_decremented = false;;
;

class MyClass 
  public:
    MyClass(MyType* mytype)
        : mytype_(mytype)
    

    void alg() 
      sub_routine_1();
      sub_routine_2();
      modify_mytype();
    ;

  protected:
    MyType* mytype_;

    virtual void sub_routine_1() = 0;
    virtual void sub_routine_2() = 0;

    void modify_mytype() 
      mytype_->increment();
    ;
;

class MyClassImpl : public MyClass
  public:
    MyClassImpl(MyType* mytype)
        : MyClass(mytype)
    

    void print() 
      mytype_->print();
    ;
  protected:
    virtual void sub_routine_1() 
      //do algorithm things here
      mytype_->increment();
      mytype_->increment();
    ;
    virtual void sub_routine_2() 
      //do more algorithm things here
      mytype_->decrement();
      mytype_->decrement();
    ;
;

int main()

    MyType* mytype = new MyTypeImpl();
    MyClass* myclass = new MyClassImpl(mytype);

    // Prints "42"
    myclass->print();

    // Do other stuff with "myclass"

    delete myclass;
    delete mytype;

请注意,我在此示例中仅使用原始指针以提高清晰度。强烈建议您不要使用newdelete,而是使用智能指针来管理指针的生命周期。

静态多态性解:

并不是说这个解决方案的设计实际上更好,但我认为这更接近你真正想要的,因为它不需要直接修改MyType 类。此外,MyClass 所需的唯一修改是使其成为模板类:

#include <iostream>

class MyType 
  public:
    virtual void increment() 
      data_++;
    

  protected:
    int data_ = 0;
;

class MyTypeImpl : public MyType

public:
    void print() 
        std::cout << data_ << std::endl;
    

    void decrement() 
        data_--;
        is_decremented = true;
    ;

protected:
    bool is_decremented = false;
;

template <typename T>
class MyClass 
  public:

    void alg() 
      sub_routine_1();
      sub_routine_2();
      modify_mytype();
    ;

  protected:
    T mytype_;

    virtual void sub_routine_1() = 0;
    virtual void sub_routine_2() = 0;

    void modify_mytype() 
      mytype_.increment();
    ;
;

template <typename T>
class MyClassImpl : public MyClass<T> 
  public:
    void print() 
      this->mytype_.print();
    ;

  protected:
    virtual void sub_routine_1() 
      //do algorithm things here
        this->mytype_.increment();
        this->mytype_.increment();
    ;
    virtual void sub_routine_2() 
      //do more algorithm things here
        this->mytype_.decrement();
        this->mytype_.decrement();
    ;
;

int main()

    // Use the template to get the correct implementation
    MyClassImpl<MyTypeImpl> myclass;

    myclass.alg();
    myclass.print();

    // Do other stuff with my class

【讨论】:

这可能是唯一的解决方案,但我想避免修改 MyType 和 MyClass(或至少避免添加与潜在实现相关的任何内容)。 MyClass 和 MyType 做了一些非常具体的事情,我想通过添加成员和方法(仅在子类中)来扩展该功能。如果 MyClass 没有对 MyType 进行操作,这可以简单地完成,但是如果我在 MyType 子类中添加一个成员,MyClass 将看不到它。 您不需要直接将实现细节添加到MyType,但是如果您想向MyTypeImpl添加可以通过MyType接口访问的新功能,您仍然需要将它们添加到MyType 的接口中,否则您无法调用它们。基本上MyType 充当多个实现的一致接口。可以提供多个MyTypeImplMyTypeImpl2等实现类,可以通过MyType接口访问。 另外,您可以考虑使用模板来实现“静态”多态性解决方案。虽然我不确定这会让你更接近你想要的。我看看能不能写个例子。 我已经用使用模板的静态多态性解决方案更新了解决方案。希望这更接近您正在寻找的内容,因为它不需要直接修改 MyType 类。 很高兴我能帮上忙 :) 希望 C++20 能够通过“概念”为此类问题提供更好的解决方案。我还不完全熟悉它们的工作原理,但我认为这实际上可能是解决这个问题的最佳方法。

以上是关于在 C++ 中可以有一个虚拟类型吗?的主要内容,如果未能解决你的问题,请参考以下文章

C++ 虚拟方法:我必须在父类中为子级和父级不共享的每个方法创建一个虚拟方法吗?

通过“函数参数”中的 const 类型在派生类中具有不同函数参数的虚拟函数会破坏虚拟机制吗? [复制]

如何在 Linux 上创建虚拟 CAN 端口? (C++)

派生类中函数的 C++“虚拟”关键字。有必要吗?

每个类都应该有一个虚拟析构函数吗?

在 C++ 中,如何使用虚拟基类型声明一个全局的、静态分配的变量?