首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >有什么方法可以用引用来做一个常量的getter吗?

有什么方法可以用引用来做一个常量的getter吗?
EN

Stack Overflow用户
提问于 2013-01-26 04:29:59
回答 2查看 652关注 0票数 0

考虑以下模式:

代码语言:javascript
复制
class Child
{
public:
    char Foo;

    Child(char foo)
    {
        Foo = foo;
    }
};

class Parent
{
public:
    Child c;

    Parent() : c('A') { }

    const Child& GetChild() const
    {
        return c;
    }
};

// Scenario 1: Works, but useless
int main()
{
    Parent p = Parent();
    Child c = p.GetChild();
    c.Foo = 'B';
    cout << p.c.Foo << endl; // A, wrong
    cout << c.Foo << endl; // B, good
    system("PAUSE");
}

// Scenario 2: Doesn't compile, of course
int main()
{
    Parent p = Parent();
    Child& c = p.GetChild(); // Error
    c.Foo = 'B';
    cout << p.c.Foo << endl; // A, good
    cout << c.Foo << endl; // B, good
    system("PAUSE");
}

规范如下:

  • 必须将getter定义为const (因为它不修改父程序)
  • getter提供的引用必须修改基础值。

问题是:

  • 如果getter本身是const,C++要求getter的返回值为const (为什么?)
  • C++禁止将const值分配给引用(逻辑上)

使用指针(使访问器返回Child*)来完成这一任务非常容易,但似乎有一种共识(而且是正确的),即引用是明智的,因为它们隐藏了指针的复杂性。

有什么办法吗?如果没有,我将回到指针。

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2013-01-26 04:32:14

如果返回的引用不是const,则调用方可以修改对象,即使它在自己的上下文中是const:

代码语言:javascript
复制
const Parent p = ...
Child & child = p.GetChild(); // valid const call, invalid return type

但是,这只是在试图返回作为类本身一部分的成员变量(它本身不是指针)时才会出现的问题。所以,正如你已经建议的,让这个孩子成为一个指针是可以的。但将非指针指针返回到非指针Child将导致同样的问题.

为了更好地说明这个问题,请考虑以下内存布局说明:

代码语言:javascript
复制
Parent:  [Child]

Child:   [char ]

因此,父对象包含一个Child对象,而不包含更多的对象,因此修改Parent实例会修改Child实例,而修改Parent::c则会修改Parent本身。

因此,您不能返回非const对象的指针或引用( this指针在const成员函数中指向的对象):

代码语言:javascript
复制
Child& GetChild() const
{
    return c;    // compiler will complain here
}

相当于:

代码语言:javascript
复制
Child& GetChild() const
{
    return this->c;   // compiler will complain here
}

其中this的类型是const Parent *,这意味着this->c的类型是const Child &。返回Child &违反了const-ness。

getter本身并不修改对象,但它允许绕过调用方代码中的const-性,如上面的代码所示。

票数 2
EN

Stack Overflow用户

发布于 2013-01-26 05:24:42

需求看起来很矛盾,因为如果不能修改父级,那么就意味着即使是子成员也不应该被修改。

但是,如果您的规范比较宽松,并且可以修改子成员对象,那么可能的解决方案是使用const_cast。

代码语言:javascript
复制
class Child
{
public:
    char Foo;

    Child(char foo)
    {
        Foo = foo;
    }
};

class Parent
{
public:
    Child c;

    Parent() : c('a') { }

    const Child& GetChild() const
    {
        return c;
    }
};

// Scenario 2: Doesn't compile, of course
int main()
{
    Parent p = Parent();
    Child& c = const_cast<Child &>(p.GetChild()); // No more Error
    c.Foo = 'B';
    std::cout << p.c.Foo << std::endl; // A, good
    std::cout << c.Foo << std::endl; // B, good
    system("PAUSE");
}
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/14533864

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档