多重继承和单例设计模式

Multiple inheritance and singleton design pattern

本文关键字:设计模式 单例 多重继承      更新时间:2023-10-16

我设置了以下类层次结构,并希望调用非单例基对象的print()函数,该函数OtherBase调用,该函数又调用其中一个子类的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而不是单例基类SingletonBaseprint函数?

我已经尝试过test->OtherBase::print(),但这不起作用。

>@MuhammadAhmad的回答基本上是正确的。 我想补充一点,这里的主要问题是C风格的演员阵容允许你做一些你真的不想做的事情。 由于无法静态地将SingletonBase强制转换为OtherBase,因此 C 样式强制转换正在执行reinterpret_cast,并且在生成的指针上调用 print() 是未定义的行为。 如果您使用了static_cast,则会出现错误:

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

错误:从类型"SingletonBase*"到类型"OtherBase*"的static_cast无效

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

SingletonChildSingletonBase继承了它instance方法,该方法返回指向SingletonBase的指针。
所以打电话给SingletonChild::instance();会让你得到一个SingletonBase*,你不能简单地投OtherBase*

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

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

然后像这样简单地调用print方法:test->print();

请参阅有关 ideone 的代码。

编辑

您也可以像这样实现:

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

也看到这种方法的实际效果。

您要做的是将 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 样式的强制转换,因为您最终可能会像它们不是的东西一样操纵对象。