题
我需要从非const对象调用const函数。见例子
struct IProcess {
virtual bool doSomeWork() const = 0L;
};
class Foo : public IProcess {
virtual bool doSomeWork() const {
...
}
};
class Bar
{
public:
const IProcess& getProcess() const {return ...;}
IProcess& getProcess() {return ...;}
void doOtherWork {
getProcess().doSomeWork();
}
};
致电
getProcess().doSomeWork();
总是会调用
IProcess& getProcess()
还有另一种方式来致电
const IProcess& getProcess() const
来自非常数成员函数? 我到目前为止使用
const_cast<const Bar*>(this)->getProcess().doSomeWork();
这可以解决问题,但似乎过于复杂。
编辑:我应该提到代码正在重构,最终只剩下一个函数。
<*>但是,目前存在副作用,const调用可能会在某些时候返回不同的IProcess实例。
请继续主题。
解决方案
避免强制转换:将其分配给 const Bar *
或其他任何内容,并使用它来调用 getProcess()
。
有一些迂腐的理由可以做到这一点,但它也使你在不强迫编译器做一些可能不安全的事情时更加明显。当然,你可能永远不会遇到这些情况,但在这种情况下你也可以编写一些不使用强制转换的东西。
其他提示
const_cast
用于投射远 constness!
你从非const转换为const是安全的,所以使用 static_cast
:
static_cast<const Bar*>(this)->getProcess().doSomeWork();
我的意思是说,你可以使用 const_cast
来强制转换为constness,但这并不是对运算符的实用性。新风格演员(与旧的C风格演员阵容相比)的目的是传达演员的意图。 const_cast
是一种代码气味,它的使用至少应该被审查。另一方面, static_cast
是安全的。但这是C ++风格的问题。
或者你可以创建一个新的(私有)const方法,并从 doOtherWork
调用它:
void doSomeWorkOnProcess() const { getProcess().doSomeWork(); }
使用const临时也是一个选项(通过“MSN”回答):
const Bar* _this = this;
_this->getProcess().doSomeWork();
如果 getProcess()
和 getProcess()const
没有返回对同一对象的引用(但是不同的限定),那么它将指示 class Bar
。在函数的 const
上重载不是区分具有不同行为的函数的好方法。
如果他们返回对同一对象的引用,则:
const_cast<const Bar*>(this)->getProcess().doSomeWork();
和
getProcess().doSomeWork();
调用完全相同的 doSomeWork()
函数,因此无需使用 const_cast
。
如果演员阵容对你来说太难看了,你可以改为向 Bar
添加一个方法,它只返回对 * this
的const引用:
Bar const& as_const() const {
return *this; // Compiler adds "const" without needing static_cast<>
}
然后,您可以通过在 as_const()。
之前调用
Bar
中的任何 const
方法,例如:
as_const().getProcess().doSomeWork();
如果函数没有重载,则不必执行任何强制转换操作。调用非const对象的const方法很好。它从被禁止的const对象调用非const方法。如果使用const和非const函数覆盖这些方法,那么将对象强制转换为const将会起到作用:
const_cast<const IProcess&> (getProcess()).doSomeWork();
编辑:我没有读完整个问题。是的,您需要const_cast this 指针或使 doOtherWork 函数const调用 const IProcess&amp; getProcess()const 。
关键在于您不需要const对象来调用 doSomeWork 。既然这是目标,你需要名为?
的const方法吗?另一种选择是重命名过度使用的功能。如果这两个函数实际上具有不同的行为/副作用,那将是一个非常好的主意。否则,函数调用的效果不会很明显。
定义模板
template< class T >
const T & addConst ( T & t )
{
return t;
}
并致电
addConst( getProcess() ).doSomeWork();
嗯,你能宣布
吗?void doOtherWork const ()
那就可以了。
我认为const_cast方法是你最好的选择。这只是C ++中const框架的一个限制。我认为唯一可以避免转换的方法是定义一个返回const IProcess实例的方法。例如。
const IProcess* getProcessConst() const { return ... }
...
getProcessConst().doSomeWork();
我假设您希望DoOtherWork调用您的两个getprocess调用之一,具体取决于是否从const对象调用它。
我能建议的最好的是:
class Bar
{
public:
const IProcess& getProcess() const {return ...;}
IProcess& getProcess() {return ...;}
void doOtherWork { // should use getProcess()
getProcess().doSomeWork();
}
void doOtherWork const {
getProcess().doSomeWork(); // should use getProcess() const
}
};
即使这样可行,这对我来说也是一种难闻的气味。我会非常警惕根据对象的常量彻底改变的类行为。
发布者monjardin
另一种选择是重命名过度使用的函数。如果这两个函数实际上具有不同的行为/副作用,那将是一个非常好的主意。否则,函数调用的效果不会很明显。
的iProcess&安培;主要通过属性
访问其他代码__declspec(property(get=getProcess)) IProcess& Process;
所以重命名不是一种选择。调用函数的大部分时间 const 都与getProcess()匹配,所以没有问题。
你基本上没有重命名其他方法或const_cast。
BTW,这是写时复制智能指针在C ++中实际上不能正常工作的原因之一。写时复制智能指针是可以无限共享的指针。当用户访问非const上下文中的数据时,会生成数据副本(如果用户未持有唯一引用)。当共享只有一些客户端需要修改的大型数据结构时,这种指针可以非常方便地使用。最“逻辑”的实现是有一个const和一个非const运算符 - >; const版本只返回底层引用。非const版本执行唯一的引用检查和复制。它没有用,因为非const智能指针将使用非const运算符 - >默认情况下,即使您想使用const版本。 const_cast要求使其对用户不友好。我欢迎任何证明我错误的人,并在C ++中展示一个用户友好的写时复制指针...