初始化const对象中的引用

时间:2014-09-02 19:43:22

标签: c++ constructor const constants

我有以下代码:

class c_int {
public:
  int &i;
  c_int(int &in) : i(in) {
  };
  c_int(const int &in) : i(in) {
  };
};


int main (void) {

  const int i = 10;
  const c_int c(i); 

  std::cout << c.i << std::endl;

  return 0;
}

编译它会显示以下错误消息:

tmp.cpp:12:30: error: invalid initialization of reference of type 'int&' from ex
presion of type 'const int'

我遇到了一些麻烦,弄清楚如何让它工作,我应该如何在const对象中初始化一个引用?

编辑:理想情况下,我希望这个对象也可用于非常量int;当对象未被声明为const时。

进一步编辑:

我也想使用这样的对象:

int main (void) {

  int i = 10;
  c_int c(i); // for some reason this calls the 2nd of my constructors, does name mangling not take const into account?
  c.i = 9;    

  std::cout << i << std::endl;

  return 0;
}

5 个答案:

答案 0 :(得分:6)

问题不在于你的对象是const:而是你试图将const引用绑定到非const引用:这是非法的。

您可以将const引用绑定到const成员:

class c_int {
public:
  const int &j;
  c_int(const int &in) : j(in){  };
};


int main (void) {

  const int i = 10;
  c_int c(i); 

  std::cout << c.j << std::endl;
}

您仍然可以为constnon const个对象使用两个不同的类,或者如果您真的需要一个类并知道您在做什么,请使用{{ 1}}(真的不鼓励:任何修改对象的尝试都是未定义的行为):

const_cast

或者,忘记通过引用传递并使用值语义:

class c_int {
public:
  int& i;
  c_int(int& in) : i(in){ }
  c_int(const int& in) : i(const_cast<int&>(in)){ } // Very wrong
};

修改

对于int参数不是const的情况,你仍然可以添加一个非const引用的构造函数:

class c_int {
public:
  int i;
  c_int(int in) : i(in){ }
};

Live demo.

答案 1 :(得分:2)

我建议你有两个不同的课程。一个持有const引用,另一个持有非const引用。这类似于标准容器将iteratorconst_iterator作为两个单独的类的方式。

class c_int {
public:
  int &i;
  c_int(int &in) : i(in) {};
};

class const_c_int {
public:
  int const &i;
  c_int(int const &in) : i(in) {};
};

如果您想避免重复代码,可以制作模板:

template<typename T>
class c_generic {
public:
  T& i;
  c_generic(T& in) :i(in) {}
};

typedef c_generic<int> c_int;
typedef c_generic<int const> const_c_int;

答案 2 :(得分:1)

我认为你混淆了const的含义。引用始终是常量(无论是否从const对象访问):您不能更改引用,作为类成员,它必须在构造函数的初始化列表中初始化。

情况与指针相同。考虑:

const int*a;              // pointer to a const int: cannot change *a, but can change a
int*const b;              // pointer to an int, cannot change b, but can change *b
const int*const c;        // constant pointer to a constant int: cannot change c nor *c

int&x;                    // equivalent to pointer b
const int&y;              // equivalent to pointer c

引用始终是常量,因此带指针的第二个const始终打开。

答案 3 :(得分:1)

您希望同一个类c_int作为const引用工作,而非const引用int依赖于&#34; constness&#34; c_int本身。不幸的是,在C ++中是不可能的。出于同样的原因,iteratorconst_iterator在STL中是不同的类型。您可以使用相同的方法:

class c_int {
public:
  int &j;
  c_int( int &in) : j(in){  }
};

class const_c_int {
public:
  const int &j;
  const_c_int( const int &in) : j(in){  }
  const_c_int( const c_int &in) : j(in.j){  }
};

因此,您可以将c_int转换为const_c_int,但反之亦然

答案 4 :(得分:1)

参考成员必须是const或不是const。并且const个对象的构造函数不可能与非iterator对象不同。

一个选项是实际上有两个不同的类,一个用于包装int,另一个用于包装const int。与const_iteratorconst的不同类型相似。这可以是通过模板参数,或者非const版本可以从const版本派生,或者它们可以完全独立。

要使用单个非模板类,您将需要使用返回引用的函数,以便在对象是否为class c_int { private: int const *p_int; bool is_const; public: c_int(int &x): p_int(&x), is_const(false) {} c_int(int const &x): p_int(&x), is_const(true) {} int &i() { if ( is_const ) throw std::runtime_error("non-const access for const int"); return const_cast<int &>(*p_int); } int const &i() const { return *p_int; } }; 时可以重载它。此外,它必须是在运行时检查的属性,因为始终可以将非const对象强制转换为const。例如:

{{1}}

有可能有一个什么都不做的默认构造函数,然后你使用一个函数来设置可变的类成员,但是你失去了构造函数的好处。