从另一个派生类调用派生类中的成员函数

Call member function in derived class from another derived class

提问人:Mike Eager 提问时间:9/4/2023 最后编辑:Mike Eager 更新时间:9/5/2023 访问量:97

问:

我有一个程序,它有一个基类和几个派生类,这些派生类包含覆盖基类成员函数的成员函数。派生类之间存在一些重复的代码,我想消除这些重复。具体而言,在其中一个派生类中,一个成员函数包含一些初始处理,然后与另一个派生类中的同一命名成员函数进行相同的处理。

下面是一个简化的示例:

#include <iostream>

class BASE 
{
public:
  virtual ~BASE() = default;
  virtual void A() { std::cout << "In BASE\n"; }
  virtual void B() { std::cout << "Shared by all instances\n"; }
  virtual void C() { std::cout << "Different in all instances\n"; }
};

class D1: BASE
{
public:
  void A() override { std::cout << "In D1\n"; }
  void C() override { std::cout << "In D1::C()\n"; }
};

class D2: BASE
{
public:
  void A() override
  {
     std::cout << "In D2\n";

     // #1
     // D1::A();        // Error cannot call D1::A() w/o object

     // #2
     // D1 *t = (D1 *) this;    // Creates recursive loop
     // t->A();                 // calling D2:A()

  }
  void C() override { std::cout << "In D2::C()\n"; }
};

int main()
{ 
  D1 d1;
  D2 d2;

  BASE *b = &d1;
  b->A();

  b = &d2;
  b->A();
}

在此示例中,我希望将 to 的调用链接到,以便我能看到来自两个成员函数的消息。我尝试了两种不同的方法来做到这一点(参见 #1 和 #2),它们都出错了。D2::A()D1::A()

正确的方法是什么?

C++ 继承成员 函数

评论

1赞 Pepijn Kramer 9/4/2023
你想解决什么问题?虚拟方法应该通过指向其基类的(唯一)指针(或引用)来调用。如果你需要你想做的事情,我怀疑存在设计问题。旁注:在派生类中,方法 A() 应该是 。而且你不应该使用void A() overrideusing namespace std;
0赞 Jan Schultke 9/4/2023
我不明白你为什么不重新调整类型层次结构,以便共享一个共同的基础,这将包含你试图删除重复的任何代码。是否允许在此处更改其层次结构的类?这需要更多细节。 显然不能被调用,因为它不是派生自 .D2D1D2D1D1::A();D2D2D1
2赞 Jarod42 9/4/2023
创建一个免费函数来共享代码?
1赞 PaulMcKenzie 9/4/2023
1) 重新分配给 时,您的内存泄漏。2) 该类缺少虚拟析构函数,因此如果要“修复”内存泄漏,调用将导致未定义的行为。mainbnew D2;BASEdelete
1赞 JaMiT 9/4/2023
@MikeEager “我可以将重复的代码移动到基类中,但该代码不适用于基类的其他用途。” -- 听起来你是在争论定义一个类,,它派生自 ,以及 和 和 派生。这里有一个有用的技巧:你能描述一下原因并分享功能吗?它们有什么相似之处?你刚才描述了一个定义吗?Intermediate1BASED1D2D1D2Intermediate1

答:

-1赞 Wyck 9/4/2023 #1

首先,除非你声明.请注意 的用法。否则,你会得到类似“类型转换”的东西:从“D1 *”到“BASE *”的转换存在,但无法访问。(MSVC)BASE *b = &d1;class D1: public BASEpublic

此外,听起来需要从中派生,以便除了任何额外的功能之外,还可以调用其实现。这样,您就可以像您提到的那样,通过在实现的末尾显式调用 来“链接”。D2D1D2::AD1::AD1::A()D2::A

#include <iostream>

class BASE 
{
public:
  virtual ~BASE() = default;
  virtual void A() { std::cout << "In BASE\n"; }
};

class D1: public BASE
{
public:
  void A() override { std::cout << "In D1\n"; }
};

class D2: public D1
{
public:
  void A() override
  {
     std::cout << "In D2\n";

     D1::A(); // Chain to D1::A
  }
};

int main()
{ 
  D1 d1;
  D2 d2;

  BASE *b = &d1;
  b->A();

  b = &d2;
  b->A();
}

预期输出:

In D1
In D2
In D1

第一个“In D1”将来自呼叫,第二条和第三条消息“In D2, In D1”将来自呼叫,因为明确地“链接”到 .b = &d1; b->A();b = &d2; b->A();D2::AD1::A

评论

0赞 Mike Eager 9/4/2023
D2 不是 D1 的适当子集;它只有一个成员函数,其代码在 D1 和 D2 中都是重复的。D1 和 D2 中的其他成员函数可能非常不同。
0赞 Mike Eager 9/5/2023
我编辑了这个例子,以明确 D1 和 D2 是独立的,不能相互推导。