23

我需要从非常量对象调用 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 的不同实例。

请继续话题。

4

11 回答 11

15

const_cast是为了摆脱constness!

您正在从非常量转换为安全的 const,因此请使用static_cast

   static_cast<const Bar*>(this)->getProcess().doSomeWork();

我的意思是从技术上讲,您可以使用 constness 进行转换const_cast,但这不是对运算符的务实使用。新风格演员表(相对于旧的 c 风格演员表)的目的是传达演员表的意图。const_cast是一种代码味道,至少应该对其使用进行审查。static_cast另一方面是安全的。但这是 C++ 风格的问题。

或者您可以创建一个新的(私有)const 方法,并从以下位置调用它doOtherWork

  void doSomeWorkOnProcess() const { getProcess().doSomeWork(); }

使用 const 临时也是一种选择(由“MSN”回答):

   const Bar* _this = this;
   _this->getProcess().doSomeWork();
于 2009-01-04T15:31:11.577 回答
10

避免强制转换:将其分配给 aconst Bar *或任何东西并使用它来调用getProcess().

这样做有一些迂腐的理由,但它也让你在不强制编译器做一些可能不安全的事情的情况下更清楚你在做什么。当然,您可能永远不会遇到这些情况,但您不妨编写一些在这种情况下不使用强制转换的东西。

于 2009-01-02T19:10:53.550 回答
5

如果演员表对你来说太难看,你可以添加一个方法来Bar简单地返回一个 const 引用*this

Bar const& as_const() const {
    return *this;    // Compiler adds "const" without needing static_cast<>
}

然后,您可以通过预先添加来调用任何 const方法,例如:Baras_const().

as_const().getProcess().doSomeWork();
于 2009-01-09T08:00:42.840 回答
4

如果getProcess()并且getProcess() const没有返回对同一对象的引用(但限定不同),则表明class Bar. 重载const函数的本质并不是区分具有不同行为的函数的好方法。

如果它们返回对同一对象的引用,则:

const_cast<const Bar*>(this)->getProcess().doSomeWork();

getProcess().doSomeWork();

调用完全相同的doSomeWork()函数,因此无需使用const_cast.

于 2009-01-02T15:42:59.197 回答
1

如果函数没有重载,你不必做任何转换技巧。调用非常量对象的 const 方法很好。它从被禁止的 const 对象调用非常量方法。如果方法被 const 和非 const 函数覆盖,那么将对象转换为 const 就可以了:

const_cast<const IProcess&> (getProcess()).doSomeWork();

编辑:我没有阅读整个问题。是的,您需要对this指针进行 const_cast 或使doOtherWork函数 const 来调用const IProcess& getProcess() const

关键仍然是您不需要 const 对象来调用doSomeWork。既然这是目标,你需要调用 const 方法吗?

另一种选择是重命名覆盖的函数。如果这两个函数实际上具有不同的行为/副作用,这将是一个非常好的主意。否则,函数调用的效果不会很明显。

于 2009-01-02T15:31:38.970 回答
1

定义一个模板

template< class T >
const T & addConst ( T & t ) 
{
    return t;
}

并打电话

addConst( getProcess() ).doSomeWork();
于 2012-12-06T10:35:17.337 回答
0

好吧,你能声明

void doOtherWork const ()

?

这样就可以了。

于 2009-01-02T15:32:49.857 回答
0

我认为 const_cast 方法是你最好的选择。这只是 C++ 中 const 框架的一个限制。我认为您可以避免强制转换的唯一方法是定义一个无论如何都返回 const IProcess 实例的方法。例如。

const IProcess* getProcessConst() const { return ... }
...
getProcessConst().doSomeWork();
于 2009-01-02T15:41:31.103 回答
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     
  }
};

即使这样可行,这对我来说似乎是一种难闻的气味。我会非常警惕根据对象的常量性而彻底改变的类行为。

于 2009-01-02T15:45:59.377 回答
0

由 monjardin 发布
另一种选择是重命名被覆盖的函数。如果这两个函数实际上具有不同的行为/副作用,这将是一个非常好的主意。否则,函数调用的效果不会很明显。

IProcess& 主要通过属性在其他代码中访问

__declspec(property(get=getProcess)) IProcess& Process;

所以重命名不是一种选择。调用函数的大部分时间常数与 getProcess() 匹配,因此没有问题。

于 2009-01-02T16:30:57.010 回答
-1

您基本上坚持重命名其他方法或 const_cast。

顺便说一句,这是写时复制智能指针在 C++ 中实际上不能正常工作的原因之一。写时复制智能指针是可以无限共享的。当用户在非常量上下文中访问数据时,会制作数据的副本(如果用户不持有唯一引用)。当共享只有部分客户端需要修改的大型数据结构时,这种指针可以非常方便地使用。最“合乎逻辑”的实现是有一个 const 和一个非常量 operator->。const 版本只返回底层引用。非常量版本进行唯一的引用检查和复制。它没有用,因为非常量智能指针默认使用非常量运算符->,即使您想使用 const 版本。

我欢迎任何证明我错了并在 C++ 中显示用户友好的写时复制指针的人......

于 2009-01-02T15:40:44.007 回答