C++ 有没有一种方法可以通过引用生成一个常量getter?

C++ 有没有一种方法可以通过引用生成一个常量getter?,c++,pointers,reference,pass-by-reference,C++,Pointers,Reference,Pass By Reference,考虑以下模式: 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:

考虑以下模式:

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");
}
类子类
{
公众:
查富;
儿童(查富)
{
Foo=Foo;
}
};
班级家长
{
公众:
儿童c;
父():c('A'){}
constchild&GetChild()常量
{
返回c;
}
};
//场景1:有效,但无用
int main()
{
父p=父();
Child c=p.GetChild();
c、 Foo='B';

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

const Parent p = ...
Child & child = p.GetChild(); // valid const call, invalid return type
但是,这只是当您试图返回属于类本身的成员变量(它本身不是指针)时的问题。因此,正如您所建议的,将子对象设置为指针是可以的。但是,将非常量指针返回到非指针
子对象
将导致相同的问题

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

Parent:  [Child]

Child:   [char ]
因此父对象只包含一个
子对象,因此修改
父实例将修改
子实例,而修改
父::c
将修改
父实例本身

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

将等于:

Child& GetChild() const
{
    return this->c;   // compiler will complain here
}
其中,
this
属于
const-Parent*
类型,这意味着
this->c
属于
const-Child&
类型。返回
Child&
违反了常量


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

这些要求看起来相互冲突,因为如果不能修改父成员,则意味着即使子成员也不应该修改

但如果您的规范是宽松的,并且子成员对象可以修改,那么一个可能的解决方案就是使用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");
}
类子类
{
公众:
查富;
儿童(查富)
{
Foo=Foo;
}
};
班级家长
{
公众:
儿童c;
父():c('a'){}
constchild&GetChild()常量
{
返回c;
}
};
//场景2:当然不会编译
int main()
{
父p=父();
Child&c=const_cast(p.GetChild());//没有更多错误
c、 Foo='B';

std::难道我不认为您有一个C++11实现,因此可以将
Child C;
成员变量标记为
mutable
,并将getter更改为just
Child&getChild()const{return C;}
?@这在C++11中是禁止的/不可能的吗?很可能(很小的机会)是UB,我必须检查一下,但我记得可变成员的全部要点是允许它们即使在常量环境中也不会很热。我非常确定我在上面发布的内容是合法的。我当然希望这不是不可能的,因为如果是的话,我的工具链就相当断裂了。@WhozCraig:这不是C++11的新功能。@BenjaminLindley
mutable
meMVAR在11辆Jeezor之前就已经存在了,我需要更多的外出。回答得好。理解的中心点来自这样一个事实,
c
,作为一种“价值类型”实际上是
const
ed
Parent
内存块的一部分,而不仅仅是一个引用。指针似乎是一个逻辑选择。或者你会对我的需要有其他建议吗?似乎你实现了一个树型数据结构。通常,你使用指针或引用来实现它们。如果它们是指向同一对象的整个生命周期(您不能“重置”引用,但可以使用指针)。在这两种情况下,指针/引用都是对象的一部分,但不是指向的对象,因此返回此类(可修改的)指针/引用是有效的。
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");
}