我目前正在尝试创建一对相互依赖的类。本质上,类 B
的对象创建类 A
的对象。但是,我还使用了继承层次结构,因此类 B
的所有派生类也必须能够创建类 A
的派生类(B
的每个派生类code> 对应于 A
的派生,因此 DerB1
生成 DerA1
对象,而 DerB2
生成 DerA2
对象)。
我的实现有问题,这可能很愚蠢,但我想看看是否有人知道该怎么做。我的代码在下面(我讨厌阅读别人的代码,所以我试图让它尽可能容易阅读......只有几个重要的部分,我评论解释)
class BaseB {} // Declare BaseB early to use in BaseA constructor
class BaseA
{
public:
BaseA(BaseB* b) {}; // Declare the BaseA constructor (callable by all B classes, which pass a pointer to themselves to the constructor so the A objects can keep track of their parent)
}
class DerA:public BaseA
{
DerA(BaseB* b):BaseA(b) {}; // Inherit the BaseA constructor, and use initialization list
}
class BaseB
{
public:
virtual BaseA createA() = 0; // Virtual function, representing method to create A objects
}
class DerB:public BaseB
{
BaseA createA() {
DerA* a = new DerA(this); // Definition of createA to make a new A object, specifically one of type DerA (Error1: No instance of constructor "DerA::DerA" matches the argument list)
return a; // Error2: Cannot return DerA for BaseA function
}
}
所以,我有两个主要问题,一个是实际问题(错误 1,因为我似乎只是错误地调用了函数,即使我尝试类型转换 this
),一个是哲学问题(错误 2 ,因为我不知道如何实现我想要的功能。如果有人能指出为什么会出现 Error1,那就太好了!但是,Error2 需要一些解释。
我希望我的用户(程序员)以相同的方式与所有 A
对象进行交互。它们将具有完全相同的公共(public)函数,但每个函数将具有非常不同的实现。有些将使用不同的数据类型(因此需要函数契约),但许多将具有相同的数据类型,只是它们使用的算法不同。如果使用一个类 A
派生类或另一个类,我希望一些代码以完全相同的方式工作。但是,在我当前的实现中,似乎我需要返回一个 DerA
对象而不是一个 BaseA
对象(在 Error2 的位置)。这意味着我需要专门为 DerA
对象编写一段主代码,而不是任意的 A
对象。我想要这样的东西:
BaseB b = new DerB(); // Declare which derivative of BaseB I want to use
BaseA a = b->createA(b); // Call the createA function in that derivative, which will automatically make a corresponding A object
这样,我可以简单地在第一行中选择我想要的 B
对象类型(通过我选择 B
构造函数、标签或模板,或其他东西),其余代码对于任何类型的对象 B
看起来都是一样的(因为每个对象都有相同的公共(public)成员函数,即使每个对象执行这些函数的方式不同)。
使用模板或其他方法而不是继承会更好吗? (我为故意含糊而道歉,但我希望我的 A/B 类示例应该主要解释我需要什么)。
感谢您的帮助。对于在一篇文章中提出两个问题和啰嗦,我深表歉意,但我正在努力学习对某些软件进行相当大的重新设计的最佳方法。
最佳答案
您有几个语法问题需要解决错误:
- 在每个类定义之后添加
;
。 - 第一行应该是前向声明:
class BaseB/*{} NO!!*/;
- 添加
public:
使DerA
的构造函数可供DerB
访问 BaseA createA()
应该返回一个值,而不是一个指针(根据签名):return *a;
还有另一个潜在的隐藏切片问题,因为createA()
返回一个值,而不是指针。这意味着您返回的对象(此处为 *a
)将被复制,但作为真正的 BaseA 对象。因此只会复制对象的 BaseA 部分,不会复制派生部分。这可能会导致一些意想不到的惊喜。
为了避免切片,考虑返回一个指针,相应地更改 createA()
的签名。指向的对象将保持正确的类型而不会丢失任何东西。
如果您稍后需要复制该对象,并且您完全确定所指向对象的真实类型,则可以使用静态转换:
BaseA *pba = pdb->createA(); // get pointer returned
DerA da = *static_cast<DerA*>(pba); // static cast with pointer
如果您需要复制指向的 BaseA 对象而不必知道它们的真实类型,您可以在 DerA 中实现一个虚拟克隆函数(例如 prototype design pattern)
关于C++:结合继承、多态和工厂,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25753687/