这是一组实现一种适配器模式的C ++类:
#include <iostream>
class Cfoo
{
public:
explicit Cfoo(int i):i_(i){}
void SetI(int i){ i_ = i; }
int GetI()const{ return(i_); }
private:
int i_;
};
class CfooHolderConst
{
public:
explicit CfooHolderConst(const Cfoo& foo):foo_(foo){}
int GetI()const{ return( foo_.GetI() ); }
private:
const Cfoo& foo_;
};
class CfooHolderNonConst
{
public:
explicit CfooHolderNonConst(Cfoo& foo):foo_(foo){};
int GetI()const{ return( foo_.GetI() ); }
void SetI(int i){ foo_.SetI(i); }
private:
Cfoo& foo_;
};
int main( int argc, char* argv[] )
{
const Cfoo myConstFoo(42);
CfooHolderConst myConstFooHolder(myConstFoo);
std::cout << myConstFooHolder.GetI() << std::endl;
Cfoo myNonConstFoo(1);
CfooHolderNonConst myNonConstFooHolder(myNonConstFoo);
myNonConstFooHolder.SetI(42);
std::cout << myConstFooHolder.GetI() << std::endl;
return(0);
}
我想将CfooHolderNonConst和CFooHolderConst组合成一个单独的类,或者失败,继承另一个类。对Cfoo的引用在这里是一个问题,因为在CFooHolderConst中它需要定义为const Cfoo&amp;,而在CfooHolderNonConst中它需要是Cfoo&amp;。
这是与interator / const_iterator类似的问题: How to avoid code duplication implementing const and non-const iterators?
...但我希望,因为这不必满足STL迭代器的要求,可能会有一个更简单的解决方案。
过去我通过将const和nonconst指针都作为类成员,并从重载的构造函数中设置一个或另一个来解决这类问题。这浪费了空间,看起来很笨拙。有更优雅的解决方案吗?
答案 0 :(得分:1)
您可以创建一个模板类,它将为该类的const和非const版本提供const功能,然后继承以扩展非const版本,并具有修改该成员的功能:
class Cfoo
{
public:
explicit Cfoo(int i):i_(i){}
void SetI(int i){ i_ = i; }
int GetI()const{ return(i_); }
private:
int i_;
};
class CfooHolderNonConst;
template<class Foo>
class CFooHolder
{
friend class CfooHolderNonConst;
public:
explicit CFooHolder(Foo& foo):foo_(foo){}
int GetI()const{ return( foo_.GetI() ); }
private:
Foo& foo_;
};
typedef CFooHolder<const Cfoo> CfooHolderConst;
class CfooHolderNonConst: public CFooHolder<Cfoo>
{
public:
explicit CfooHolderNonConst(Cfoo& foo):CFooHolder(foo){};
void SetI(int i){ foo_.SetI(i); }
};
答案 1 :(得分:1)
是的,可以做到:
template< typename T > CHolderReader
{
public:
explicit CHolderBase( T& t):t_(t){}
int Get()const { return t_.GetI(); }
protected:
~CHolderReader() {}
protected:
T& t_;
};
template< typename T > CHolderReaderWriter : public CHolderReader< T >
{
public:
void Set( int i)
{
t_.SetI(i);
}
};
typedef CHolderReader<const Cfoo> CFooHolderConst;
typedef CHolderReaderWriter<Cfoo> CFooHolderNonConst;
实际上,这是一个将底层数据的获取包装在const或非const状态的示例。除非模板化类型是const,否则读者持有非const引用,但不允许您写入它,因此当您需要写入时,可以像使用CHolderReaderWriter一样扩展它。
答案 2 :(得分:0)
我认为将const-和非const-接口都作为一个单独的类是个好主意。
它们为用户提供不同的接口,并具有不同的语义。在您的示例中,复制也很少。
答案 3 :(得分:0)
如果你真的想拥有相同的类(提供语义仍然有意义),那么我想你想要的东西:
const Cfoo f1( 5 );
const CfooHolder h1( f1 );
Cfoo f2( 0 );
CfooHolder h2( f2 );
我认为你希望C ++做出以下决定:
a)将 Cfoo 对象视为const
,如果它是const
,或者将非const视为非常量。线索既是 Cfoo 的定义,也是 CfooHolder 的定义。如果 Cfoo 为const
,则 CfooHolder 必须声明为const
,否则无法编译。如果 Cfoo 是非常量的,那么您可以创建 CfooHolder ,这可以是const
和非 - const
。
b)当在const CfooHolder对象中使用时,方法SetI()
应该停止编译。在上面的示例中,h1.SetI( 6 );
不应该编译。
我的回答是,如果a)工作,那么b)也会自动工作。问题是实现a),据我所知,这是不可能的。
为了使其正常工作,该属性应该在其类的对象的const或非const的环境下成为const
或非const。虽然该类的对象可以更改此“状态”,但属性保持不变。但是,当此类的对象为const
时,您只能使用const
方法(例如,通过常量引用传递参数时)。所以,C ++不会支持它,因为它不会那样工作。
另一种可能性是让属性本身同时为const和非const,这没有意义。
简短的回答是:它无法完成,并且会有代码重复。如果你真的想要避免这种情况,并且包装器足够复杂而不必担心,唯一的方法是创建一个通用的持有者,然后围绕一般持有者的常量和非常量包装器,避免重复到最小的。< / p>
class CfooHolder
{
public:
explicit CfooHolder(Cfoo& foo):foo_(foo){};
int GetI()const{ return( foo_.GetI() ); }
virtual void SetI(int i){ foo_.SetI(i); }
protected:
Cfoo& foo_;
};
class CfooHolderNonConst : public CfooHolder {
public:
explicit CfooHolderNonConst(Cfoo& foo):CfooHolder(foo){};
};
class CfooHolderConst: public CfooHolder
{
public:
explicit CfooHolderConst(const Cfoo& foo):CfooHolder(const_cast<Cfoo &>( foo )){}
void SetI(int i){ throw std::runtime_error( "Don't write to me!" ); }
};
它并不完美,但它符合所述条款。方法SetI()
会抛出运行时错误,但如果 CfooHolderConst 对象声明为const
,则对SetI()
的调用甚至不会编译。< / p>
希望这有帮助。
答案 4 :(得分:0)
是否有一个特定原因导致您不能仅将FooHolder
用于非const(可变)访问,而const FooHolder
用于const访问?
你不能在const对象上调用非const限定的方法(如SetI
),所以看起来它就像你想要的那样。显然,你最初需要从非const Cfoo
创建持有者对象。
示例:
class Cfoo
{
public:
explicit Cfoo(int i) : i_(i) {}
void SetI(int i) { i_ = i; }
int GetI() const { return(i_); }
private:
int i_;
};
class CfooHolder
{
public:
explicit CfooHolder(Cfoo& foo) : foo_(foo) {};
void SetI(int i) { foo_.SetI(i); }
int GetI() const { return( foo_.GetI() ); }
private:
Cfoo& foo_;
};
void bar(CfooHolder &holder, int i)
{
holder.SetI(i); // fine
}
void bar(CfooHolder const &constholder, int i)
{
holder.SetI(i);
// error: method exists, but I can't call it here
}