我的问题是基于典型的钻石层次结构,但不是典型的钻石问题。
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
,其中我无法指定默认构造函数的默认值(永远不会被调用)?或者我做错了什么?
答案 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)
莫因,
首先,我认为你必须为ImpOne
和ImpTwo
声明一个构造函数。否则他们会在构建时尝试调用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