【问题标题】:Call through the base class abstract method [duplicate]通过基类抽象方法调用[重复]
【发布时间】:2018-01-31 01:49:46
【问题描述】:

我有一个接口,用户从中派生多个我不知道的类,但我仍然想将这些派生类称为公共方法Run().

Event 类旨在成为一个接口,因此我知道如何调用我的 unknown UserEvents 派生类,因为它们都必须实现 Run() 方法。

我目前有一些代码并收到CallEvent can't allocate an abstract Event 的错误。我理解错误,但不知道如何正确执行。

这是一些最小的代码示例 (WandBox):

#include <iostream>

class Event
 {
 public: 
      virtual void Run(int Param) = 0;
 };

 // This is a user event and I have no idea what the class name is,
 // but I still have to call it's method Run() that is common to the interface "Event"
 class UserEvent : public Event
 {
 public:
      virtual void Run(int Param) { std::cout << "Derived Event Dispatched " << Param << std::endl;};
 };

 // This parameter is of pure abstract base class Event because
 // I have no idea what my user class is called.
 void CallEvent(Event WhatEvent)
 {
      WhatEvent.Run(123);
 };

 int main()
 {
      std::cout << "Hello World!" << std::endl;
      UserEvent mE;
      CallEvent(mE);
 }

【问题讨论】:

  • mE 按值传递给接受事件的 CallEvent。这称为切片。更改 CallEvent 以获取指针或引用。
  • void CallEvent(Event WhatEvent) 更改为 void CallEvent(Event&amp; WhatEvent)。 (这是理查德克里顿所说的。)
  • 谢谢,成功了!如果我收到UserEvent* mE = nullptr 并做了诸如WhatEvent = new Event(); 之类的事情,是否可以达到相同的效果? Like so
  • 你不能 new Event() 因为 class Event 是抽象的(纯 virtual Run() 方法)。如果class Event 不是抽象的,CallEvent() 会有什么意义?它得到一个指针WhatEvent,它用Event 的新实例覆盖它。此外:如果WhatEvent 是指针,则选择运算符.WhatEvent.Run(123) 中是错误的。相反,您必须使用WhatEvent-&gt;Run(123);。所以,CallEvent() 应该是:void CallEvent(Event *WhatEvent) { if (WhatEvent) WhatEvent-&gt;Run(123); }if (WhatEvent) 确保Event::Run() 的调用只针对非nullptrs 完成......
  • ...否则非法。

标签: c++ abstract-class virtual


【解决方案1】:

我获取了您的示例代码 (Like so) 并尝试使其运行(用于说明):

#include <iostream>

class Event {
  public: 
    virtual void Run(int Param) = 0;
};

// This is a user event and I have no idea what the class name is,
// but I still have to call it's method Run() that is common to the interface "Event"
class UserEvent: public Event {
  public:
    virtual void Run(int Param)
    {
      std::cout << "Derived Event Dispatched " << Param << std::endl;
    }
};

// This parameter is of pure abstract base class Event because
// I have no idea what my user class is called.
void CallEvent(Event *WhatEvent)
{
  std::cout << "in CallEvent(Event *WhatEvent):" << std::endl;
  // Huh? WhatEvent = new Event();
  // wrong: WhatEvent.Run(123);
  // Instead, use ->.
  // For pointers, check for non-nullptr is very reasonable:
  WhatEvent->Run(123);
  // obsolete: delete WhatEvent;
}

// second approach using a reference (as recommended in comments):
void CallEvent(Event &WhatEvent)
{
  std::cout << "in CallEvent(Event &WhatEvent):" << std::endl;
  WhatEvent.Run(123); // for references - select operator . is fine
}

int main()
{
  std::cout << "Hello World!" << std::endl;
  /* nullptr does not make sense:
   * UserEvent *mE = nullptr;
   * Go back to original approach:
   */
  UserEvent mE;
  CallEvent(&mE); // calling the first (with Event*)
  CallEvent(mE); // calling the second (with Event&)
  return 0;
}

现在,它是可编译和可运行的。输出:

Hello World!
in CallEvent(Event *WhatEvent):
Derived Event Dispatched 123
in CallEvent(Event &WhatEvent):
Derived Event Dispatched 123

ideone 上的生活演示)

我在示例代码中注释了 cmets 中的每一个修改。

【讨论】:

  • 请不要在 C++ 中使用原始指针。参考是您应该显示的唯一变体。
  • @bolov 一般来说,只要没有真正的理由使用指针,我更喜欢引用。而不是原始指针(非常危险),我尽可能喜欢智能指针。但是,提问者的链接示例代码暴露了我想要修复的指针解决的尝试。因为我也想考虑参考,所以我展示了这两种解决方案。
猜你喜欢
  • 1970-01-01
  • 2016-06-20
  • 1970-01-01
  • 2018-07-11
  • 1970-01-01
  • 1970-01-01
  • 2019-12-12
  • 2018-07-16
  • 2020-08-09
相关资源
最近更新 更多