标题有点模糊,但我想不出更好的措辞,这是交易:
class A
{
public:
A();
A( const PropertyB& b );
PropertyA GetPropertyA();
PropertyB GetPropertyB();
SetPropertyA( const PropertyA& b );
SetPropertyB( const PropertyB& b );
//assignment not allowed
};
假设我想使用一个 std::vector< A >,但是,只有当它的所有元素对 PropertyB 具有相同的值时,拥有一个 A 的 vector 才有意义。当前的解决方案是提供一个类似于构造器的方法来创建这样的数组,它保证返回数组的所有元素对 PropertyB 具有相同的值,以及一个检查是否是这种情况的方法:
Array MakeArray( size_t, const PropertyB& );
bool CheckIfArrayIsSane( const Array& );
所以用户仍然可以在元素上调用 SetPropertyB(),但是有一个实用程序来检查它并在有人这样做时退出:
Array x( MakeArray( 3, someValue ) );
x.SetPropertyA( aaa ); //should be allowed
x.SetPropertyB( someOtherValue ); //should NOT be allowed
//somewhat further in the program
if( !CheckIfArrayIsSane( x ) )
throw InsaneArrayExcpetion();
虽然这行得通,但它很容易出错,因为很难在所有地方强制执行此检查并且不会忘记它,并且检查会使代码困惑。
不有效的方法:
- 将 SetPropertyB() 设为私有(private),并将 MakeArray 设为友元函数:这样一来,对于只想使用 A 而不关心数组的用户而言,SetPropertyB() 将无法再访问。
- 将 std::vector< A > 包装在一个单独的类中并且只返回 const A& 引用:这意味着其他 setter 如 SetPropertyA() 也不能被调用,但用户应该能够调用它们。只有 SetPropertyB() 应该被禁止。
一种更具侵入性的方法可行但感觉有点不雅,并且需要额外的函数在两者之间进行转换等:
class AWithFixedPropertyB
{
public:
A( const PropertyB& b );
PropertyA GetPropertyA();
PropertyB GetPropertyB();
SetPropertyA( const PropertyA& b );
};
class A : public AWithFixedPropertyB
{
public:
//contrcutors etc
SetPropertyB( const PropertyB& b );
};
//ok, users cannot modify property B in this Array
typedef std::vector< AWithFixedPropertyB > Array;
这个问题最优雅的解决方案是什么?
最佳答案
从 OO 设计的角度来看,这没有意义。还记得 Liskov 比喻原则吗:只要 A 对象可以用来代替 B 对象,A is-a B?根据该规则,您提议的元素 std::vector<A>
is-an-A 测试失败,因为您无法设置它们的 B 属性。然而std::vector<A>
应该是 A 对象的容器。
在 C++ 中,我们有私有(private)继承,这明确表明派生类不与其父类有 is-a 关系。您可以按如下方式使用它:
class A_fixed_B : private A
{
A_fixed_B(A const& src) : A(src) {}
A const& asA() const { return *this; } // Base Conversion is OK inside class.
using A::GetPropertyA;
using A::GetPropertyB;
using A::SetPropertyA;
};
您现在可以创建 std::vector<A_fixed_B>
其行为可能符合您的预期。
关于c++ - 强制具有相同属性的 vector 元素的优雅方式,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6150761/