2013-04-22 67 views
4

我有一些代码已经被写入而不考虑const的正确性。有没有在改变这个添加const正确性

class X 
{ 
public: 
    X(X& rhs); // does not modify rhs 
    ... 
}; 

这个

class X 
{ 
public: 
    X(const X& rhs); 
    ... 
}; 

将改变现有的程序的行为的情况?我知道这种改变会允许当前没有编译的代码进行编译,但是如果有任何已编译的代码会改变它的行为的情况,我很感兴趣。

类似的问题,是否有任何优点,而不是改变?

class X 
{ 
public: 
    X(X& rhs); // does not modify rhs 
    X(const X& rhs); 
    ... 
}; 
+0

我可以看到我的问题已被轻微误解。我不问如何重写复制构造函数,我的问题是在给定使用类X的大量代码时是否存在任何危险。此代码是由完全不知道const并且正在使用编译器不关心。现在在移植到一个新的编译器时,我剩下的代码不能编译,并且我不能在STL中使用类。 – john 2013-04-22 17:15:55

回答

2

对于复制构造函数我不这么认为。但请注意,一般来说,是的,const的声明可以影响调用哪个方法。唯一想到的例子是数组重载 - 参见例如this question

0

由于您正在更改具有复制构造函数的类,我假设您可以检查复制构造函数代码。如果你可以做这个改变,并且复制构造函数不会给出编译器错误,那么你可能是好的。要考虑的一个案例是复制赋值操作符,因为没有保证,特别是在优化的代码中会被调用。所以也要确保你的拷贝分配可以使用一个const参数。

+1

您可以举一个例子,您不能确定是否会调用复制构造函数或赋值运算符? – Agentlien 2013-04-22 12:46:30

+0

这是来自我问过的一个问题。 http://stackoverflow.com/questions/9267687/understanding-eliding-rules-with-regard-to-c11 – rerun 2013-04-22 12:48:06

+0

据我所知,这只意味着你不能确定副本是否会被删除。无论如何,当您(有理由)期望复制构造函数时,我不会看到赋值运算符会被调用的情况,反之亦然。 – Agentlien 2013-04-22 12:52:32

1

事实上,复制构造函数应该,imho,总是以const引用作为参数。

X(X& rhs) { } // does not modify rhs 

这不允许复制常量对象,因此下面的代码不会编译。 虽然非const对象可以作为常量参数,倒过来是不可能的

X const test; 
X new_x(test); 

我不能想象为什么有人要排除一个const对象的副本。

关于您想要进行的更改: 复制构造函数是否依赖于非const定义的任何X成员函数?

这工作就像一个魅力,但允许复印const对象:

class X 
{ 
private: 
    int a; 
public: 
    X(X &rhs) { a = rhs.value(); } 
    int& value (void) { return a; } 
}; 

下一个示例将无法编译,因为rhs是常量,但value()不是常量。

class X 
{ 
private: 
    int a; 
public: 
    X(X const &rhs) { a = rhs.value(); } 
    int& value (void) { return a; } 
}; 

如果你想让你的类的常量正确,你可能需要检查整个类。 它应该只会影响您的课堂实施。因为我不知道外部代码应该依赖于类成员函数的“非常量”的情况。 除非我的例子中的任何公共成员函数返回非const引用。

以下代码片段将按照预期执行。

class X 
{ 
private: 
    int a; 
public: 
    X(int const &b) : a(b) { } 
    X(X const &rhs) { a = rhs.value(); } 
    int const & value (void) const { return a; } 
}; 

但要知道,这将像任何干扰代码:

X test(100); 
test.value() = 12; 

此使用int& value (void) { return a; }会工作,但失败int const & value (void) const { return a; }。 你当然可以提供两个安全的方面。

0

djechlin在his answer作出重要的一点,虽然有点不清楚,所以我会尽力解释更好。

对象或引用的常量影响重载解析。举例来说,如果你有一个成员函数的const基于超载的对象,不同的重载将被选择:现在

struct foo { 
    void do_stuff(); 
    void do_stuff() const; 
}; 

int main() { 
    foo f; 
    const foo& fr = f; 

    f.do_stuff(); // calls non-const version 
    fr.do_stuff(); // calls const version 
} 

,如果重载之一,具有副作用,其他没有,你” d改变签名后会得到不同的行为,假设(或者,即使)程序编译得很好。