【问题标题】:Passing a pointer to one derived class to another将指向一个派生类的指针传递给另一个派生类
【发布时间】:2015-12-30 17:43:47
【问题描述】:

我仍在学习 C++ 的基础知识,但我目前正在开发一个使用派生类和虚拟方法的项目。所以情况是: 我有一个A类

class ClassA
{
public:
    virtual void action();
};

还有两个派生类B和C:

#include "ClassA.h" 

class ClassB: public ClassA
{
public:
    virtual void action();
    int valueB;
};

-

#include "ClassA.h"

class ClassC: public ClassA
{
public:
    virtual void action();
    int valueC;
};

我想将指向 ClassB 对象的指针作为 ClassC 中 action() 的参数传递,所以我可以这样做:

void ClassC::action(ClassB * ptr)
{
cout << "The value is: " << ptr->valueB;
}

但是我找不到可行的方法来做到这一点。所有的对象指针都存储在一个

vector<ClassA *> objects

在哪里

objects[0]=new ClassC();
objects[1]=new ClassB();

如果我尝试类似的东西

objects[0]->action(object[1])

然后我需要我在 ClassA 中的虚拟方法有一个参数 ClassB *。然后让程序识别我尝试包括整个 ClassB.h 的类型(坏主意,它会创建包含的“循环”或其他东西)或使用前向声明类 ClassB; (我收到有关无效使用不完整类型的错误)。所以我现在被困住了。我希望一切都清楚,但如果需要,我当然可以提供更多数据。

【问题讨论】:

  • 对。因为盲目地将A* 转换为B* 是不安全的
  • 如何摆脱 valueB 和 valueC 而只拥有一个 int 值;在 A 类?
  • 您将在另一个类的标题中使用 ClassB 类的前向声明,并在 cpp-File 中包含 include。与 Sentinel 一起,如下所述,它将避免循环...

标签: c++ class pointers


【解决方案1】:

当您需要转发声明某些内容时,这是因为您不能包含类的整个定义。在这种情况下,如果您转发声明ClassB,编译器不知道其成员属性valueB,这就是您收到不完整类型错误的原因。要解决此问题,您必须将代码分解为:

//ClassA.h
class ClassB;

class ClassA
{
  virtual void action(ClassB* ptr);
}

//ClassA.cpp
#include "ClassB.h"
void ClassA::action(ClassB* ptr) { ... }

所以你基本上是使用头声明虚方法并转发声明ClassB,但是你在ClassA.cpp中定义它,这样在源文件中你可以包含ClassB.h,没有问题,也没有风险循环依赖。

【讨论】:

  • 我刚刚测试了这个解决方案,效果非常好。唯一的区别是我在 ClassC.cpp 中包含了 ClassB.h 而不是 ClassA.cpp。您的解决方案导致相同的错误(不完整类型)。我不知道为什么,但可能是因为 ClassC.h 包含 ClassA.h(前向声明在哪里)但不知道 ClassA.cpp(实际定义在哪里)?
【解决方案2】:

我注意到你的 ClassC 虚函数被声明为不带参数:

virtual void action();

但是您使用参数定义派生类函数。

void ClassC::action(ClassB * ptr)

声明和定义必须匹配。将声明更改为:

virtual void action(ClassB *);

嗯。但是你必须在 ClassC 声明之前包含 ClassB...

#include "ClassB.h"

或转发声明ClassB。这是对编译器稍后正确声明和定义类的承诺。插入这一行的好地方是在 ClassC 声明之前。

class ClassB;

【讨论】:

  • 答案还不错。但是,读者应该如何知道在哪里插入前向声明呢?请注意,OP 仍然学习 C++ 的基础知识。
  • 编辑建议放置前向声明的地方。感谢您的帮助。 :)
【解决方案3】:

您可以将action(在所有类中)定义为:

virtual void action(ClassA * ptr); // or ClassB *

然后你可以传递 ClassA 的任何实例或从 ClassA 派生。 所有派生类都可以包含带有#include "ClassA.h" 的 ClassA,如果您在 header-File 中提供 Sentinel,因为它在 c++ 中很常见:

#ifndef ClassAH
#define ClassAH

...

#endif

因此,标题将只包含一次...

【讨论】:

  • 不确定,但我认为 OP 请求了 ClassB * 类型的参数。
  • 您在两者之间进行了编辑。 ClassB * 不能在没有前向声明的参数列表中使用。
  • 你是对的。如果你想使用 ClassB,你可以在另一个类的头文件中使用 ClassB 的前向声明和 cpp-File 中的 include。与 Sentinel 一起,它将避免循环。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2023-04-07
  • 2012-12-26
  • 1970-01-01
  • 2013-08-15
  • 1970-01-01
  • 2021-09-09
  • 1970-01-01
相关资源
最近更新 更多