我有以下代码:
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;
}
答案 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;
}
您仍然可以为const
和non 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){ }
};
答案 1 :(得分:2)
我建议你有两个不同的课程。一个持有const引用,另一个持有非const引用。这类似于标准容器将iterator
和const_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 ++中是不可能的。出于同样的原因,iterator
和const_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_iterator
和const
的不同类型相似。这可以是通过模板参数,或者非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}}
有可能有一个什么都不做的默认构造函数,然后你使用一个函数来设置可变的类成员,但是你失去了构造函数的好处。