class Foo
{
int Bar;
public:
int& GetBar() const
{
return Bar;
}
}
GetBar
方法是一个const
方法,这样做可以吗?它实际上并没有改变任何内容,但它为“外部世界”提供了一种改变它的手段。
class Foo
{
int Bar;
public:
int& GetBar() const
{
return Bar;
}
}
GetBar
方法是一个const
方法,这样做可以吗?它实际上并没有改变任何内容,但它为“外部世界”提供了一种改变它的手段。
你的代码中有一个错别字,这可能是你想表达的:
class Foo
{
int Bar;
public:
int& GetBar() const
{
return Bar; // Removed the ampersand, because a reference is returned, not an address
}
}
不,这是不合法的。使用const
标记一个方法时,你承诺不会更改对象的任何内部状态,同时也承诺不会返回任何可以用于更改对象状态的内容。非const
引用可以用于修改GetBar()
作用域外的Bar
值,因此你暗示自己无法遵守此承诺。
你必须将该方法更改为非const
,返回一个const
引用,或通过将Bar
标记为mutable
使其免于承诺。例如:mutable int Bar;
mutable
关键字告诉编译器对象的逻辑常量性不取决于Bar
的状态。然后你可以对其进行任何操作。
Bar
,而不是&Bar
。无论如何,我在Comeau中放置了这段代码:class Foo
{
int Bar;
public:
int& GetBar() const
{
return &Bar;
}
};
int main(int argc, char** argv)
{
Foo x;
int y = x.GetBar();
y = 5;
return 0;
}
并且收到了以下错误:
line 9: error: qualifiers dropped in binding reference of type
"int &" to initializer of type "const int"
return Bar;
^
return Bar;
。const
方法中,您有一个const
this
指针(在您的情况下,它将是一个const Foo *
),这意味着您可以获取到其字段1的任何引用都将是一个const
引用,因为您是通过“const
路径”访问它们。const int &
(从Bar
获取的引用)初始化int &
(您的方法的返回值),显然这是被禁止的。testconstref.cpp: In member function ‘int& Foo::GetBar() const’:
testconstref.cpp:9: error: invalid initialization of non-const reference of type ‘int&’ from a temporary of type ‘const int*’
这就是我刚才说的。:)
相反,如果你从一个const
方法返回一个const
引用到一个类字段,你不会有任何问题。
mutable
的字段,这告诉编译器这样的字段即使从const
方法中也是可修改的;这个例外是为了允许const
方法在不改变对象的“逻辑”状态的情况下改变其“真实”状态;这可以用于实现惰性求值、引用计数等...不行,因为您无法执行以下赋值操作:
const int x; int &y = x;
但您可以执行以下操作:
const int x; const int &y = x;
当然,您也可以对方法进行重载,并创建常量和非常量变体,没有问题。
Bar
是int
而不是const int
,但在GetBar() const
的上下文中它是"const int"。因此,将它作为非const引用或指针返回与执行以下操作一样是非法的:
const int y = 57;
int& z = y;
即使第二行尚未实际更改y,它也会破坏const-correctness。class A
{
Foo * foo;
public:
Foo * getFoo() const // legal. does not have to return const Foo *
{
return foo;
}
};
mutable
,则可以通过非const引用返回Bar
,因为这些成员不受成员函数的const限制。const
修饰符用于成员函数时,不允许在其作用域内更改对象的状态。编译器只检查该函数是否在其作用域内修改了对象的状态。举个例子:
class foo
{
int num ;
public :
foo( int anum )
{
anum = 10;
}
int getNum()
{
return num;
}
};
foo obj;
int& myNum = obj.getNum() ; // myNum is just an alias to the private class variable num
myNum = 40; // Actually changes the content of the private variable.
因此,编译器只检查访问说明符(即,这个变量在这个作用域中是否可访问),但不会检查私有/公共/受保护变量的内存位置是否返回给其他变量。