我有一段代码是这样的:
class EducationalCentre
{
string _centreName;
vector<Course> _courses; // courses offered by the Centre
Collection<Course*, Student*, 150> _applicants;
public:
EducationalCentre(string name="<name>")
{
_centreName = name;
}
EducationalCentre(const EducationalCentre& obj)
:_courses(obj._courses), _applicants(obj._applicants)
{
_centreName = obj._centreName;
}
};
现在,在这部分 _applicants(obj._applicants)
复制构造头文件,(obj
周围有一条波浪形的红线,将其悬停在错误说明类型不兼容的情况下(提到了 const
)。
因为我不想在这个阶段改变任何东西(这是考试的一部分)- 我想知道为什么会这样。
我尝试从 EducationalCentre(const EducationalCentre& obj)
中删除 const
并且确实解决了问题但是..正如我所说,我宁愿了解导致此问题的原因而不是删除它。
使用规则const
就是尽可能使用它:)
当然,就像所有最佳实践一样,也有异常(exception),但总的来说,您应该始终努力制作非静态方法 const
如果它们不改变对象的状态。
您遇到问题的原因是 Collection
复制构造函数对其用作源对象的实例进行非常量引用。
复制构造函数可以将 const 或非 const 引用作为其参数,但是,IMO,非 const 应该只在您别无选择时使用,这种情况很少见。基于另一个对象创建对象不应更改源对象,因此应标记为 const
.
正如我在评论中指出的那样,泛型类与采用 const 引用的复制构造函数无关。确实,如果您看一下例如std::vector
你会看到它有一个复制构造函数,它接受一个 const 引用。可能是你在Collection
中使用的一些方法你的参数上的复制构造函数是非常量的,这就是为什么你不能使参数为常量的原因。解决方案是让违规方法也成为 const。
这给我们带来了重要的一点:const
尼斯是病毒式的。如果您将一个方法标记为常量,则它调用自身的所有其他方法也必须是常量。在 const 对象上调用方法也是如此——你只能调用 const 方法。如果您不从一开始就这样做,您最终可能会遇到这样的情况:将一个方法设为 const 会导致更改其他方法的整个链,因此更容易放弃。
为什么 constness 是好的:大多数错误都是由以意想不到的方式改变应用程序状态引起的——只要问问对不变性赞不绝口的函数式编程爱好者就知道了:)。 const 方法无法更改对象的状态,因此它消除了意外更改的可能性:例如如果在 const 方法中间抛出异常,您可以确定该对象不处于某种使类不变量无效的半修改状态。
现在,C++不仅仅是一种面向对象的语言,所以你可以通过其他方式改变应用程序的状态,你也可以滥用mutable
和 const_cast
欺骗编译器,但使用 const
对编写正确的软件和减少调试工作有很大帮助。