使用 non-const 构造 const 对象

Constructing const object using non-const

本文关键字:对象 const 构造 non-const 使用      更新时间:2023-10-16

我有一个带有构造函数的类,该构造函数接受分配给该类成员的非常量引用。现在我想创建该类的 const 对象,但是如果我将 const 引用传递给构造函数,构造函数会抱怨。下面的代码是对我原始代码的简化,演示了这个问题。

据我所知,创建一个 const 对象应该没有问题,因为它是基于 const 数据的?

如何在create_const_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;
}

我得到的错误是:

test.cc: In function ‘const A create_const_a(const double&, const int&)’:
test.cc:27:17: error: binding ‘const double’ to reference of type ‘double&’ discards qualifiers
   return A(dd,ii);
                 ^
test.cc:8:3: note:   initializing argument 1 of ‘A::A(double&, const int&)’
   A(double &dd, const int &ii)
   ^

更新:在学习了一些关于 const 如何处理其中的对象和非 const 引用的新知识后,我最终通过引入另一种类型解决了原始问题,比如 ConstA 只包含 const 引用,然后可以在每个有问题的情况下使用。

C++禁止这样做,以避免将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的引用,这是未定义的行为。

这是一个小演示:

int x = 10;
cout << x << endl;
const foo f(x);
f.bar();
cout << x << endl;

它打印

10
5
函数

const A create_const_a将常量双精度的引用作为第一个参数,然后尝试在ctor中将其用作不允许的非常量引用。

应在此处删除const限定符。

如果你

真的确定为什么你可以在这里这样做,这意味着如果你可以确定create_const将全部接收非常量参数,你可以显式使用 const_cast 来删除限定符:

const A create_const_a(const double &dd, const int &ii) {
  return A(const_cast<double &>(dd),ii);
}

请注意,如果您在最初声明为 const 的变量上执行此操作,这将导致未定义的行为。

你试图放弃const

const A create_const_a(const double &dd, const int &ii) {
  return A(dd,ii);
}

但是dd是一个非常量,所以创建的对象A不知道它不能修改它d成员,而create_const_a的调用者会传递变量。

你不能不复制dd,或者放弃const(例如通过const_cast),这是危险的,强烈表明设计中的错误。

你对A的定义是"我需要能够修改d",但在create_const你承诺它不会被修改。

换句话说,您应该解决设计中的错误。释放约束或创建副本。让"错误消失"只会消除糟糕设计的症状,直到当违反合同最终产生影响时,你会陷入真正的麻烦。