设计模式-如何在C++中组合共享同一基类的两个类



我举下面的例子来说明我的问题:

class Base
{
 public:
   virtual void do()=0;
}
class A: public Base
{
public:
  void do();
};
class B: public Base
{
 public:
  void do();
}
class AB: public Base
{ 
 public:
 void do()
  {
     a_.do();
     // if not succeed
     {
        b_.do();
     }
    }
private:
 A a_;
 B b_;
}

从上面的代码中,我们可以看到类A, BAB来自同一个基类。然而,类AB需要调用类A和类B。我的问题是:AB类的潜在问题是什么?还有其他选择吗?

一种替代方案可能是:

class Base
{
 public:
   virtual void do()=0;
}
class A: public Base
{
public:
  void do();
};
class B: public Base
{
 public:
  void do();
}
class AB: public A
{ 
 public:
 void do()
  {
     A::do();
     // if not succeed
     {
        b_.do();
     }
    }
private:
 B b_;
}

我不知道你真正想要实现什么。但是,如果所有类都应该只有一个来自Base的实例数据副本,则需要一个虚拟基类。

AB的第一个例子的问题是,你有三个!乘以Base类的数据。一个来自inherit Base,一个作为成员B的一部分,成员B本身来自Base,另一个来自成员A。这是你想要的吗?

我给你以下剪辑,看看你如何在所有的类实例中使用一个精确的Base副本。也许这就是你想要的?

我向Base添加了一些数据,以了解在使用虚拟基类时构造是如何工作的。重要的是,基类构造函数不会从直接继承类的构造函数中调用!您需要直接从最外层的构造函数调用构造函数,如AB类构造函数中所示!

备注:只有在没有其他适合设计的情况下,才应该使用虚拟基类。这种解决方案的需求往往显示出设计问题。但在编程中一如既往:如果这完全符合您的需求,那么从技术上讲,这样做是完全可以的

class Base
{   
    private:
        std::string text;
    public:
        Base( const std::string& str ): text(str) {}
        virtual void Do() { std::cout << text << std::endl; }
};  
class A: virtual public Base
{   
    public:
        A():Base("Default from A") {}
        void FuncA() { std::cout << "FuncA" << std::endl; }
       void Do() { std::cout << "Via A" << std::endl; Base::Do();}
};  
class B: virtual public Base
{   
    public:
        B(): Base ("Default from B") {}
        void FuncB() { std::cout << "FuncB" << std::endl; }
};  
class AB: public A,B 
{   
    public:
        //Important to know that init of Base MUST be done from here and not from A nor B !!
        AB( const std::string &s): Base(s) {}
        void Do() { std::cout << "Via AB" << std::endl; Base::Do(); A::Do(); B::Do();}
};  
int main()
{   
    A a;
    a.Do();
    std::cout << "####" << std::endl;
    B b;
    b.Do();
    std::cout << "####" << std::endl;
    AB ab("Hallo"); 
    ab.Do();
    std::cout << "####" << std::endl;
}   

AB类的潜在问题是什么?

我不知道你的设计会产生什么众所周知的问题。你应该问问自己"为什么会出现问题?"。

还有其他选择吗?

有很多选择。例如,AB都不包含任何状态,所以您也可以停止使用类来支持自由函数,并用函数指针替换动态绑定。

为了能够比较不同的替代方案,你应该首先决定你试图解决什么问题。

您应该从A和B继承,而不是从Base继承,因为A和B已经继承了。

最新更新