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