C++:包含继承、多态性和工厂



我目前正在尝试创建一对相互依赖的类。本质上,类B的对象创建类A的对象。然而,我也在使用继承层次结构,所以类B的所有导数也必须能够创建类A的导数(B的每个导数对应于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,因为我不知道如何实现我想要的功能。如果有人能指出错误1发生的原因,那就太好了!然而,错误2需要一些解释。

我希望我的用户(程序员)以相同的方式与所有A对象交互。它们将具有完全相同的公共函数,但每个函数都有非常不同的实现。有些人将使用不同的数据类型(因此需要函数契约),但许多人将使用相同的数据类型,只是使用不同的算法。如果使用一个类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都是一样的(因为每个对象都有相同的公共成员函数,即使每个对象执行这些函数的方式不同)。

使用模板或其他方法代替继承会更好吗?(我很抱歉故意含糊其辞,但我希望我的A/B类例子应该主要解释我需要什么)。

谢谢你的帮助。我很抱歉在一篇帖子中问了两个问题,也很冗长,但我正在努力学习对一些软件进行大规模重新设计的最佳方法。

您有几个语法问题需要解决:

  • 在每个类定义之后添加;
  • 第一行应该是正向声明:class BaseB /*{} NO!!*/ ;
  • 添加public:,使DerB可以访问DerA的构造函数
  • 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中实现虚拟克隆功能(例如原型设计模式)

最新更新