C++ 良好实践:恒定到非恒定浇铸

C++ 良好实践:恒定到非恒定浇铸,c++,casting,constants,conventions,C++,Casting,Constants,Conventions,当函数不修改对象参数时,我总是让它请求一个常量引用,即使引用的对象不是真正的常量。这是错的吗 对于包装器类,我想写以下内容: template<class B> class Wrapper{ private: B* base_; public: Wrapper(const B& b) { base_ = const_cast<B*>(&b); } void ModifyBase(); }; 模板 类包装器{ 私人: B*基准; 公众: 包装器

当函数不修改对象参数时,我总是让它请求一个常量引用,即使引用的对象不是真正的常量。这是错的吗

对于包装器类,我想写以下内容:

template<class B>
class Wrapper{
private:
  B* base_;
public:
  Wrapper(const B& b) { base_ = const_cast<B*>(&b); }
  void ModifyBase();
};
模板
类包装器{
私人:
B*基准;
公众:
包装器(常量B&B){base_u=const_cast(&B);}
void ModifyBase();
};
构造函数不修改基,因此它要求一个常量引用

包装器有一些方法需要修改基址,以便它需要存储一个非常量指针(因此转换)

我觉得我的解决方案不是最好的

有更好的方法吗


是否有任何可接受的约定?

当您选择参数作为
常量
引用时,您告诉用户“您可以相信,如果您向我传递一个对象,它将不会[通过此引用]†被修改。”您应该尽可能经常这样做,因为用户可以通过查看类型来更多地了解您的函数将做什么和不做什么。此外,传递可变引用可能导致难以推理的代码

然而,在你的问题中,你的
常量
没有说实话。它丢弃了
const
属性并存储了一个非
const
指针-这意味着对象很可能会被修改。你对用户撒了谎!构造函数本身对对象不做任何操作并不重要。它允许其他成员函数对其进行修改。这是不好的行为。构造函数不应采用
const
引用

不仅如此,您当前的实现还允许未定义的行为。即使最初声明为
const
的对象被提供给
包装器
,它也不在乎。它抛弃了它的
const
ness,并允许其他成员函数修改它。修改原来是常量的对象是未定义的行为


†参见6502的评论

实际上,
ctor
不会改变
ctor
中的对象并不重要,完成
ctor
后发生的事情就是为什么需要一个指向
B
的非
常量
对象指针。所以它与传入的
B
对象的所有权和生存期有关:如果您想获得所有权(通过
&
引用,那么对象必须是非
常量
,因为它可以更改。如果您只想复制传入的
B
对象,那么就不要使用引用,通过值传递并存储指向副本的指针。

如果您想修改参数,我想这是错误的。据我所知,
常量
rgument的意思是“我只需要看到这个值-我不会用它做任何事情!”
X const X;Wrapper w(X);w.ModifyBase();
并且您有未定义的行为。不要去掉const,除非您只想弄乱类型系统(不推荐的API,DRY)。如果您打算修改对象,请不要去掉常量。这并不完全正确。承诺是“如果您传递给我一个对象,我不会使用此引用修改它”;调用一个知道该对象并对其进行变异的全局函数是完全可以的。另一个例子是,如果将同一对象传递给接受常量引用和非常量引用的函数两次,则可以对该对象进行变异(使用第二个引用):传递常量引用并不意味着承诺不修改对象。“常量引用”promise只是关于该引用,并没有告诉任何关于该对象的信息。@6502这是不正确的:通过常量和非常量引用传递同一对象,通过常量引用的常量转换应用的修改是未定义的行为!@DieterLücking:似乎您错过了“(使用第二个引用)”部分。请注意,无论如何你都错了:如果对象不是常量(这是
const_cast
的设计目的),从常量引用中去掉常量并使用它修改对象是完全正确的。@6502看一看:7.1.6.1(3/4)@ didil ucc:这是关于<代码> const 对象。const对象和const引用是C++中的两个非常不同的概念。我们通常把“所有者”称为负责破坏对象的代码的一部分。因此<代码>和<代码>是所有权的转移。