C++ 使用非常量构造常量对象
我有一个带有构造函数的类,它接受分配给类成员的非常量引用。现在我想为这个类创建一个const对象,但是如果我向构造函数传递一个const引用,构造函数就会抱怨。下面的代码是对我的原始代码的简化,它演示了这个问题 就我所知,创建const对象应该没有问题,因为它是基于const数据的 如何实现我在C++ 使用非常量构造常量对象,c++,constructor,constants,C++,Constructor,Constants,我有一个带有构造函数的类,它接受分配给类成员的非常量引用。现在我想为这个类创建一个const对象,但是如果我向构造函数传递一个const引用,构造函数就会抱怨。下面的代码是对我的原始代码的简化,它演示了这个问题 就我所知,创建const对象应该没有问题,因为它是基于const数据的 如何实现我在create\u const\u a中的目标 #include <iostream> class A { private: double &d; const int &
create\u const\u a
中的目标
#include <iostream>
class A {
private:
double &d;
const int &i;
public:
A(double &dd, const int &ii)
: d(dd), i(ii)
{}
void set_d(double a) {
d = a;
}
void print() const {
std::cout << d << " " << i << std::endl;
}
};
A create_a(double &dd, const int &ii) {
return A(dd,ii);
}
const A create_const_a(const double &dd, const int &ii) {
return A(dd,ii);
}
void foo(A a)
{
a.set_d(1.3);
a.print();
}
void bar(const A a)
{
a.print();
}
int main(int argc, char *argv[])
{
double d = 5.1;
int i = 13;
foo(create_a(d,i));
bar(create_const_a(d,i));
return 0;
}
更新:在学习了一些关于const如何处理对象和对象中的非const引用的新知识之后,我最终通过引入另一种类型解决了原来的问题,比如说
ConstA
,它只包含const引用,然后可以在每个有问题的情况下使用。C++禁止这样做,以避免将const
引用转换为非const
下面是一个小例子,说明了这将如何发生:
struct foo {
int& a;
foo(int& b) : a(b) {}
void bar() const {
a = 5;
}
};
上面的编译很好,因为a=5
不会更改foo
对象的状态;它更改外部int
的状态,因此foo::bar
允许为const
现在假设我们可以这样做:
const foo make_const(const int& x) {
return foo(x); // Not allowed
}
这样我们就可以写作了
const foo f(make_const(10));
f.bar();
并修改对临时int
的引用,这是未定义的行为
下面是一个小例子:
您正试图删除
const
ness:
const A create_const_a(const double &dd, const int &ii) {
return A(dd,ii);
}
但是dd
是一个非常量,因此创建的对象a
不会知道它不能修改它的d
成员,而create\u const\u a
的调用者则会这样传递变量
您必须复制dd
,或删除const
(例如,通过const\u cast
),这是危险的,并强烈表明设计中存在错误
您对A
的定义是“我需要能够修改d
”,但在create\u const
中,您承诺不会修改它
换句话说,您应该解决设计中的错误。释放约束或制作副本。使“错误消失”只会使糟糕设计的症状消失,直到违反合同的行为最终引起反响时,你会陷入真正的麻烦。函数
const A create\u const\u A
将常量double的ref作为第一个参数,然后尝试将其作为非常量ref使用,这是不允许的
您应该在此处删除const
限定符
如果您确实确定为什么可以在此处执行此操作,这意味着如果您可以确保create\u const
始终接收非常量参数,则可以明确使用const\u cast
删除限定符:
const A create_const_a(const double &dd, const int &ii) {
return A(const_cast<double &>(dd),ii);
}
const A create_const_A(const double&dd,const int&ii){
返回A(const_cast(dd),ii);
}
但是,请注意,如果对最初声明为常量的变量执行此操作,将导致未定义的行为。可以从非常量转换为常量,但不能从非常量转换为常量。构造函数需要一个非常量,而您的
create\u const\u a
将接收一个常量。所有这些引用。。。如果你继续,你迟早会找到一个指针,在那里你有一个悬而未决的引用,坏事就会发生。为什么在A
类中有引用?您试图用这样的解决方案解决的实际问题是什么?您的create\u const\u a
方法返回对本地对象的引用。这不像你想象的那样有效。有关详细信息,请参阅。@FrançoisAndrieux No它返回对临时对象的引用。幸运的是,它是一个const
引用,它延长了对象的生命周期,直到使用它的表达式结束。这仍然不是一个好主意,但在这个非常特殊的情况下它会起作用。好吧,返回对局部变量的引用显然是无效的,但不知何故,返回const引用似乎很好。但这是一个单独的讨论,不影响当前的问题。我现在更新了这个问题以删除它。引用可以在不违反常量正确性的情况下更改这一事实对我来说是全新的,并解释了为什么这似乎是不可能的。@kalj这是const
-ness应用于引用和指针时最棘手的部分。指针或引用可以是const
,而它们指向/引用的项将保持可写状态。
10
5
const A create_const_a(const double &dd, const int &ii) {
return A(dd,ii);
}
const A create_const_a(const double &dd, const int &ii) {
return A(const_cast<double &>(dd),ii);
}