返回引用的常量方法

24
class Foo
{
    int Bar;

    public:

    int& GetBar() const
    {
        return Bar;
    }
}

GetBar方法是一个const方法,这样做可以吗?它实际上并没有改变任何内容,但它为“外部世界”提供了一种改变它的手段。


我认为你已经回答了你的问题。此外,在例子中,Bar已经是公共的。 - XAder
"&Bar" 的类型是 "const int*",而不是 "int&"。你的编译器应该会告诉你这样做是不行的。 - CB Bailey
你试过编译了吗?编译器告诉你什么了? - David Rodríguez - dribeas
@Charles:这条评论和我帖子上的评论都很有道理,所以我删除了我的帖子。谢谢。 :-) - Nawaz
6个回答

31

你的代码中有一个错别字,这可能是你想表达的:

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的状态。然后你可以对其进行任何操作。


4
您可能想要返回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;
                 ^

4
首先,要返回一个引用,您不需要在所引用的对象上使用和号运算符;如果您想获得一个指向它的指针,则需要使用它。因此,我假设您想编写return Bar;
然后,不,您不能这样做;在一个const方法中,您有一个constthis指针(在您的情况下,它将是一个const Foo *),这意味着您可以获取到其字段1的任何引用都将是一个const引用,因为您是通过“const路径”访问它们。
因此,如果您尝试在该代码中执行您所做的操作,您将会得到编译错误,因为您将尝试使用const int &(从Bar获取的引用)初始化int &(您的方法的返回值),显然这是被禁止的。
g++实际上说:
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引用到一个类字段,你不会有任何问题。


  1. 排除标记为mutable的字段,这告诉编译器这样的字段即使从const方法中也是可修改的;这个例外是为了允许const方法在不改变对象的“逻辑”状态的情况下改变其“真实”状态;这可以用于实现惰性求值、引用计数等...

4

不行,因为您无法执行以下赋值操作:

const int x; int &y = x;

但您可以执行以下操作:

const int x; const int &y = x;

当然,您也可以对方法进行重载,并创建常量和非常量变体,没有问题。


1
当你在一个const方法中时,你的类成员被认为是常量。因此,虽然在你的类中Barint而不是const int,但在GetBar() const的上下文中它是"const int"。因此,将它作为非const引用或指针返回与执行以下操作一样是非法的: const int y = 57; int& z = y; 即使第二行尚未实际更改y,它也会破坏const-correctness。
值得注意的是,如果你的类有指针成员,唯一的const是指针本身而不是它们所指向的内容。(通常被称为“浅层”constness)
因此,这是合法的:
class A
{
  Foo * foo;

  public:
    Foo * getFoo() const // legal. does not have to return const Foo *
    {
       return foo;
    }
};

请注意,在您的原始代码中,如果mutable,则可以通过非const引用返回Bar,因为这些成员不受成员函数的const限制。

0

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.

因此,编译器只检查访问说明符(即,这个变量在这个作用域中是否可访问),但不会检查私有/公共/受保护变量的内存位置是否返回给其他变量。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接