0

考虑以下模式:

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(因为它不修改 Parent)
  • getter 给出的引用必须修改基础值

问题是:

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

使用指针很容易做到这一点(使访问器返回Child*),但似乎有一个共识(并且理所当然地)认为引用是可取的,因为它们隐藏了指针的复杂性。

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

4

2 回答 2

2

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

const Parent p = ...
Child & child = p.GetChild(); // valid const call, invalid return type

但是,这只是当您尝试返回作为类本身一部分的成员变量(它本身不是指针)时的问题。因此,正如您已经建议的那样,将 Child 设为指针就可以了。但是将非常量指针返回到非指针Child会导致同样的问题......

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

Parent:  [Child]

Child:   [char ]

因此,父对象包含一个Child对象,仅此而已,因此修改您的Parent实例会修改一个Child实例,而修改Parent::c会修改Parent它自己。

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

Child& GetChild() const
{
    return c;    // compiler will complain here
}

将等于:

Child& GetChild() const
{
    return this->c;   // compiler will complain here
}

where thisis of type const Parent *,这意味着 that this->cis of type const Child &。返回Child &违反了 const-ness。

getter 本身不会修改对象,但它允许规避调用者代码中的 const-ness,如上面的代码所示。

于 2013-01-26T04:32:14.393 回答
0

要求看起来很矛盾,因为如果 Parent 不能被修改,那么这意味着即使是 Child 成员也不应该被修改。

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

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");
}
于 2013-01-26T05:24:42.277 回答