使用非const构造const对象

时间:2017-01-18 11:55:19

标签: c++ constructor const

我有一个带有构造函数的类,该构造函数接受一个非const引用,该引用被赋给该类的成员。现在我想创建一个所述类的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引用,然后可以用于每个有问题的案例。

3 个答案:

答案 0 :(得分:2)

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的引用,这是未定义的行为。

这是一个小demo

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

打印

10
5

答案 1 :(得分:0)

您正试图放弃const ness:

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

但是dd是非const的,因此创建的对象A不会知道它不能修改它的d成员,而create_const_a的调用者会通过变量相信如此。

你无法复制dd,或放弃const(例如通过const_cast)这是危险的,并强烈表明设计中存在错误。< / p>

您对A的定义说“我需要能够修改d”,但在create_const中您保证不会修改它。

换句话说,您应该解决设计中的错误。释放约束或制作副本。让“错误消失”只会使糟糕设计的症状变得沉寂,直到你在违反合同时遇到真正的麻烦时才会产生影响。

答案 2 :(得分:0)

函数const A create_const_a将ref作为const double的第一个参数,然后尝试在ctor中使用它作为非const ref,这是不允许的。

您应该在此处删除const限定符。

如果您确定可以在此处执行此操作,则表示如果您确定create_const将始终接收非const参数,则可以明确使用const_cast删除限定符:

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

BEWARE ,如果您对最初声明为const的变量执行此操作,则会导致未定义的行为。