【问题标题】:Multiple inheritance and singleton design pattern多重继承和单例设计模式
【发布时间】:2017-02-11 11:26:52
【问题描述】:

我设置了以下类层次结构,并希望调用非单例基对象 OtherBaseprint() 函数,该函数又从子类之一调用 printSymbol(),在这种情况下SingletonChild。我知道这是一个复杂且看起来有些不必要的层次结构和做事方式,但这是一项任务,我必须以这种方式去做。

我的问题的一个例子如下:

#include <iostream>
using namespace std;

class Object
{
    virtual void print() = 0;
};

class SingletonBase : public Object
{
private:
    static SingletonBase* theOnlyTrueInstance;
protected:
    SingletonBase()
    {
        if(!theOnlyTrueInstance)
            theOnlyTrueInstance = this;
    }
    virtual ~SingletonBase(){}
public:
    static SingletonBase* instance()
    {
        if (!theOnlyTrueInstance) initInstance();
        return theOnlyTrueInstance;
    }
    void print()
    { cout<<"Singleton"<<endl; }
    static void initInstance()
    { new SingletonBase; }
};

SingletonBase* SingletonBase::theOnlyTrueInstance = 0;

class OtherBase : public Object
{
public:
    virtual string printSymbol() = 0;
    void print()
    { cout<<printSymbol(); }
};

class SingletonChild : public SingletonBase , public OtherBase
{
public:
    string printSymbol()
    {
        return "Test";
    }
    static void initInstance()
    { new SingletonChild; }
};

int main() {
    SingletonChild::initInstance();
    OtherBase* test = (OtherBase*) SingletonChild::instance();
    test->print();
    return 0;
}

如何让实例test 调用一个基类OtherBase 而不是Singleton 基类SingletonBaseprint 函数?

我尝试过test-&gt;OtherBase::print(),但没有成功。

【问题讨论】:

  • 您只想让您的test 对象调用OtherBaseprint 方法而不是SingletonBase 的方法?
  • @MuhammadAhmad 是的,差不多就是这样。

标签: c++ inheritance design-patterns singleton static-variables


【解决方案1】:

@MuhammadAhmad 的回答基本上是正确的。我想补充一点,这里的主要问题是 C 风格的演员表允许你做一些你真的不想做的事情。因为您不能将SingletonBase 静态转换为OtherBase,所以C 样式转换正在执行reinterpret_cast,并且在结果指针上调用print() 是未定义的行为。如果你使用了static_cast,你会得到一个错误:

OtherBase* test = static_cast<OtherBase*>(SingletonChild::instance());

错误:从类型“SingletonBase*”到类型“OtherBase*”的静态转换无效

这可能让你意识到你需要做一些不同的事情。例如,您可以使用dynamic_cast 像这样向侧面投射。

【讨论】:

    【解决方案2】:

    SingletonChildSingletonBase 继承它的instance 方法,该方法返回一个指向SingletonBase 的指针。
    所以调用SingletonChild::instance(); 会得到一个SingletonBase*,你不能简单地将其转换为OtherBase*

    尝试先将其转换为SingletonChild*,然后再转换为OtherBase*

    OtherBase* test = (OtherBase*)((SingletonChild*)SingletonChild::instance());
    

    然后像这样调用print方法:test-&gt;print();

    请参阅code on ideone

    编辑

    你也可以这样实现:

    SingletonChild* test = (SingletonChild*)SingletonChild::instance();
    test->OtherBase::print();
    

    也见this method in action

    【讨论】:

      【解决方案3】:

      您要做的是将 SingletonBase* 类型的对象转换为 OtherBase* 类型,这不可能因为SingletonBase 不是从OtherBase 派生的。如果您使用 dynamic_cast 而不是旧的、已弃用的 C 样式转换,您会立即意识到这种情况。

      要解决这个问题,需要修改代码如下:

      class Object
      {
          virtual void print() = 0;
      };
      
      class SingletonBase : public Object
      {
      private:
          static Object* theOnlyTrueInstance;
      protected:
          SingletonBase()
          {
              if(!theOnlyTrueInstance)
                  theOnlyTrueInstance = this;
          }
          virtual ~SingletonBase(){}
      public:
          static Object* instance()
          {
              if (!theOnlyTrueInstance) initInstance();
              return theOnlyTrueInstance;
          }
          void print()
          { cout<<"Singleton"<<endl; }
          static void initInstance()
          { new SingletonBase; }
      };
      
      Object* SingletonBase::theOnlyTrueInstance = 0;
      
      class OtherBase : public Object
      {
      public:
          virtual string printSymbol() = 0;
          void print()
          { cout<<printSymbol(); }
      };
      
      class SingletonChild : public SingletonBase , public OtherBase
      {
      public:
          string printSymbol()
          {
              return "Test";
          }
          static void initInstance()
          { new SingletonChild; }
      };
      
      int main() {
          SingletonChild::initInstance();
          OtherBase* test = dynamic_cast<OtherBase*>(SingletonChild::instance());
          test->print();
          return 0;
      }
      

      您应该避免 C 风格的强制转换,因为您最终可能会像操作对象一样操作对象。

      【讨论】:

        猜你喜欢
        • 2019-07-20
        • 1970-01-01
        • 1970-01-01
        • 2011-01-19
        • 2013-08-16
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多