为什么C ++不允许在复制ctor中进行非const到const的转换?

时间:2009-07-31 16:04:40

标签: c++ const copy-constructor

我有两个吸气成员:

Node* prev() { return prev_; }
int value()  { return value_ }

请注意缺少const标识符(我忘了它们,但现在我想知道为什么这不起作用)。我想把它编译成:

Node(Node const& other) : prev_(other.prev()), value_(other.value()) { }

编译器拒绝此操作。我认为C ++允许在函数参数中进行非const到const转换,例如:

{
   Foo(int bar);
}

Foo(const int bar)
{
   //lala
}

为什么它不能让我用复制构造函数做同样的事情? const标识符意味着我保证不会改变任何东西,那么为什么从const或非const源获取我的值会有什么影响呢?

5 个答案:

答案 0 :(得分:14)

您不是要尝试进行非const到const的转换。您试图调用两个不是const的const方法(调用prev和value)。 const语义严格禁止这种类型的操作。

您可以做的是直接使用字段prev_和value_。因为它是相同类型的成员,所以您可以访问const对象上可用的私有。

答案 1 :(得分:3)

  

我认为C ++允许在函数参数中进行非const到const转换,例如:

你正试图做相反的事情:Const到非const。调用非const成员函数时,编译器会将表达式(Node const绑定到Node&以绑定this指针)。因此它将删除const - 不允许,因为它会在const对象上调用非const函数。

/* class Foo */ {
   Foo(int bar);
}

/* Foo:: */ Foo(const int bar)
{
   //lala
}

那个代码完全是另一回事。它声明了一个函数(构造函数)两次,唯一的区别是一次参数是const,另一次不是。两次函数的类型都是相同的,因此它们不会发生冲突(const参数只会在函数体内产生影响 - 它不会对调用者产生任何影响)。此外,此代码不包含任何调用(假设第一个块在某个函数内)。

如果您想知道:如果以上两个版本相同 - 为什么不是以下?那么这是因为下面包含另一个间接层:下面,引用本身(顶层)不是const(你不能直接将const放在引用本身上) ,但引用的类型是const。此时,在确定函数类型时,const 被忽略。

/* class Foo */ {
   Foo(int &bar);
}

// different thing, won't work!
/* Foo:: */ Foo(const int &bar)
{
   //lala
}

答案 2 :(得分:2)

你是对的 - const意味着你保证不会改变任何东西。编译器通过不允许您调用该对象上的方法来保证您的承诺,这些方法本身不会保证不会更改任何内容。

答案 3 :(得分:2)

在构造函数Node(Node const& other)的声明中,参数other被声明为const。这意味着您只能在其上调用const方法。

您正在从构造函数中调用other.prev()other.value()这两个方法都是非const方法,因此编译器会抱怨。

答案 4 :(得分:2)

正如其他人所提到的,你在const对象上调用非const方法,编译器不允许这样做。

一个简单的解决方法就是将你的getter函数标记为const:

Node* prev() const { return prev_; }
int value()  const { return value_; }

因为他们不修改对象;现在可以使用const对象调用它们。实际上,无论如何都应该这样做,以便类的用户可以使用const对象调用这些getter。

但是,如果您的副本看起来像:

,那么您还有另一个潜在的问题
Node(Node const& other) : prev_(other.prev()), value_(other.value()) { }

副本和原始文件都将指向其prev_成员中的同一个Node对象。根据类语义,这可能没问题,但可能是所有权问题或其他逻辑不一致。