C ++如何初始化抽象基类引用元素?

时间:2014-04-06 13:35:27

标签: c++ inheritance virtual-inheritance diamond-problem

我的问题是基于典型的钻石层次结构,但不是典型的钻石问题。

class Interface
{
public:
    int value; 
    // SomeBigData &data; 
    Interface(int _value = 0) : value(_value) {}; 

    virtual void function1() = 0; 
    virtual void function2() = 0; 
};

class ImpOne : public virtual Interface
{
public:
    void function1() { ++value; }
};

class ImpTwo : public virtual Interface
{
public:
    void function2() { --value; }
};

class Device : public ImpOne, public ImpTwo
{
public:
    Device() : Interface(7) {}; 
};

有一个定义许多功能的抽象接口(上面的例子是简化的)。然后是实现类,一次只实现其中的一些功能。最后,有一个非抽象类,如上面的类Device,通过将几个实现类组合在一起来实现整个接口。

现在,问题是:

Interface类中有一个整数元素,它由类Device初始化,并在实现类之间共享,到目前为止一直很好。但是如果我从= 0构造函数中删除Interface(int _value = 0),整个系统就会崩溃,因为我缺少Interface类的默认构造函数,这有点奇怪,因为它永远不会被调用。

为什么这会打扰我?正如代码中所建议的,Interface类需要包含对复杂数据结构的引用(不属于类),而不是在所有派生实现类之间共享。然而,为参考指定默认值既不明智也不可能。

所以问题是:

如何正确初始化接口类(引用)元素,例如代码中建议的SomeBigData &data,其中我无法指定默认构造函数的默认值(永远不会被调用)?或者我做错了什么?

3 个答案:

答案 0 :(得分:0)

你可以这样做:

class Interface {
public:
    int value; 
    virtual SomeBigData& getBigData() = 0;
    Interface(int _value = 0) : value(_value) {}; 

    virtual void function1() = 0; 
    virtual void function2() = 0; 
};

class BigDataProvider : public virtual Interface {
public:
    SomeBigData& data_;
    BigDataProvider(SomeBigData& data) : data_(data) {}
    SomeBigData& getBigData() { return data_; }
};

class Device : public BigDataProvider, public ImpOne, public ImpTwo {
public:
    Device(SomeBigData& data) : BigDataProvider(data), Interface(7) {}
};

同样的模式也可以用于您的成员value。那么Interface将是一个“纯粹的界面”,你可以完全避免钻石类布局。

答案 1 :(得分:0)

您可以声明默认构造函数而不实现:(https://ideone.com/ZD336z

class Interface
{
public:
    Interface(int _value, SomeBigData &data) : value(_value), data(data) {}
    ~Interface() {}

    virtual void function1() = 0;
    virtual void function2() = 0;
protected:
    Interface(); // No implementation
protected:
    int value;
    SomeBigData &data;
};

该方法对于派生类应该是可见的,但不需要实现,因为只调用其他构造函数。

答案 2 :(得分:0)

莫因,

首先,我认为你必须为ImpOneImpTwo声明一个构造函数。否则他们会在构建时尝试调用Interface(),这是不存在的。 其次,您可以使用Composite Pattern来避免钻石问题。

class Interface                         // abstract
{
protected:
    Base() {}

public:
    virtual void f1(int &value) {}
    virtual void f2(int &value) {}
}

class ImpOne: Base                    
{
public:
    void f1(int &value) { value++; }
}

class ImpTwo : Base                    
{
public:
    void f2(int &value) { value--; }
}

class DeviceBase                        // abstract base for all "Devices"
{
protected:
    int value;
    List<Interface*> Leaves;            // use std::vector or whatever dependent 
                                        // on your library
    Composite(int val) { value = val; }

public:
    void f1()
    {
        for (Interface* const leaf : Leaves)
            leaf->f1(value);
    }

    void f2()
    {
        for (Interface* const leaf : Leaves)
            leaf->f2(value);
    }
}

class Device : DeviceBase
{
public:
    Device(int val) : DeviceBase(val)
    {
        Leaves << new ImpOne(value);
        Leaves << new ImpTwo(value);
    }
}    

Greez Albjeno