【问题标题】:Is it possible to use a derived class virtual method from a base class non-virtual method?是否可以从基类非虚拟方法使用派生类虚拟方法?
【发布时间】:2020-10-21 00:46:14
【问题描述】:

我有多个扩展同一个基类的派生类。它们具有相同的属性,但可能具有不同参数和主体的单个方法除外。我怎样才能有一个 std::unique_ptr 并调用派生类的方法?

这是我目前所知道的:

  1. 函数模板不能是virtual;
  2. 不能用不同的签名覆盖纯虚函数;
  3. 函数指针需要知道所有可能的派生函数的参数列表

这是我目前的倾向(没有成功):

基类:

class IBase
{
  /** ... **/
  template <class T, typename ...Args>
  MyCustomType perform(T &obj, Args ... args)
  {
    std::bind(obj->run, args);
  }

  virtual MyCustomType run(...) = 0;
};

派生类:

class Derived : IBase
{
  /** ... **/
  virtual MyCustomType run(MyType1 a, MyType2 b, bool c) override
  {
    /* code */
  }
};

我希望能够使用指向基类的指针,调用basePtr-&gt;perform(a, b, c) 和子类Derived 中的方法来执行。这有意义吗?

【问题讨论】:

  • Dervied 实际上并没有派生自任何东西(可能只是一个错字?)。您可能必须手动编写所有重载。
  • "纯虚函数不能重载" - 不正确。函数总是可以重载的,不管它们是不是纯函数。也许你的意思是覆盖?根据定义,纯函数必须始终被覆盖。但是,您不能做的是以一种方式声明一个虚拟/纯函数,然后尝试使用不同的参数在后代中覆盖它,如您的示例所示。这是行不通的。被覆盖的函数必须与被覆盖的函数匹配相同的签名。事实上,在 C++11 中添加了 override 关键字来强制执行此操作。
  • @JesperJuhl "一个纯函数可以有一个实现" - 是的,但它也必须在后代中被覆盖。这就是将virtual 方法声明为纯方法的全部意义所在。非纯 virtual 方法不必被覆盖,但纯 virtual 方法必须被覆盖。但是,如果需要,该覆盖可以调用默认实现。
  • virtual dispatch 似乎是适合这里工作的错误工具。仅给定一个IBase*,如果每个派生类的run 方法具有不同的签名,您将如何调用run
  • @HenriqueSabino 在派生类中指定 virtual 在覆盖基方法时是可选的。一旦方法被标记为virtual,它在所有后续后代中始终是虚拟的。

标签: c++ oop gcc polymorphism c++14


【解决方案1】:

我想我对最初的想法有一个可能的解决方案,使用Variadic Function Templates

class IBase
{
  template <typename ... Args>
  MyType run(Args... as)
  {
    MyType result;
    return result;
  }
};

那我可以在Derived重载这个方法:

class Derived : IBase
{
  /** ... **/
  MyType run(const MyOtherType &X, const int &a);
};

谁能想到这个解决方案的问题?

【讨论】:

  • 那行不通,因为Derived::run 不会覆盖IBase::run。它们是同名的不相关方法。所以没有办法通过IBase指针调用Derived::run
【解决方案2】:

除了可能具有不同参数和主体的单个方法

这不是 C++ 允许您直接做的事情。 C++ 是一种静态类型语言;函数的调用者和被调用者必须静态地就传递的内容和返回的内容达成一致。期间。

您尝试做的唯一选择是使用静态类型擦除,如std::any 或类似技术(如将数据隐藏在void* 后面,但这是非常危险的)。也就是说,您可以通过存储在any 中的值的tuple 将“参数”传递给函数。并且返回值也可以是any

但是,发送代码必须确切地知道接收代码期望什么,反之亦然;在不确切知道您期望在那里的情况下,您无法打开 any 的包装。所以接口是通用的,但是接收者和发送者仍然必须对到底发生了什么达成一致。

而且您绝对不希望接收函数一遍又一遍地尝试一堆不同的转换来确定提供了哪组参数以及调用哪个函数体。

一般来说,您应该尽可能避免使用此类接口,因为它们很容易出错。

【讨论】:

  • 他可以构建一个函数列表,每个函数都是绑定在一起的Derived/Method对,然后执行这个函数列表。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2016-03-31
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-09-30
  • 1970-01-01
  • 2013-09-02
相关资源
最近更新 更多