提问者:小点点

代理对象的常量正确性


我对下面的代码感到困惑,其中类baz通过代理类bar授予对其内部数据的访问权限:

struct Foo{};

template<class T>
struct Bar 
{
    Bar(T &val_): val(val_) {}

    T &val;
};

struct Baz 
{
    Bar<const Foo> get() const {return Bar<const Foo>(foo);}
    Bar<Foo>       get()       {return Bar<Foo>      (foo);}
    Foo foo;
};

struct FooBaz
{
    FooBaz(Baz &baz_): baz(baz_) {}
    // Bar<const Foo> get() const {return baz.get();} // this do not compile
    Bar<const Foo> get() const {return const_cast<const Baz &>(baz).get();} // the const_cast seems to be required
    Baz &baz;
};

似乎我必须执行一个const_cast来分派到正确的baz::get()函数。

我不明白的第一件事是,如果foobaz::baz是一个普通的baz而不是一个引用,那么它可以工作:

struct Foo{};

template<class T>
struct Bar 
{
    Bar(T &val_): val(val_) {}

    T &val;
};

struct Baz 
{
    Bar<const Foo> get() const {return Bar<const Foo>(foo);}
    Bar<Foo>       get()       {return Bar<Foo>      (foo);}
    Foo foo;
};

struct FooBaz
{
    FooBaz(Baz &baz_): baz(baz_) {}
    Bar<const Foo> get() const {return baz.get();} // Ok
    Baz baz;
};

我对const函数成员的理解是,它使这个成为const的指针,但实际上我并不完全清楚它的含义。。。 所有的数据成员都是‘就像它们是常量’吗? 对此有明确的提法吗?

另一件有趣的事情是,如果我使用std::reference_wrapper作为代理类,那么它在没有const_cast:

#include <functional>

struct Foo {};

struct Baz 
{
    std::reference_wrapper<const Foo> get() const {return std::cref(foo);}
    std::reference_wrapper<Foo>       get()       {return std::ref (foo);}
    Foo foo;
};

struct FooBaz
{
    FooBaz(Baz &baz_): baz(baz_) {}
    std::reference_wrapper<const Foo> get() const {return baz.get();} // Ok
    Baz &baz;
};

std::reference_wrapper有什么神奇之处?

谢啦!


共2个答案

匿名用户

如果foobaz::baz是普通的baz而不是引用,则可以工作:

这才是重点。 在const成员函数中,数据成员也被视为const。 请注意,对于引用,这意味着引用成员本身,而不是被引用的对象。 即baz将变成baz&; 常量baz;(常量引用),而不是baz常量& baz;(引用常量)。 事实上,引用不能进行常量限定,常量限定符只是被忽略,因为即使在const成员函数中,baz.get();也始终调用非常量的get()

对于std::reference_wrapper版本,它没有改变,baz.get();仍然调用非常量get()并返回std::reference_wrapperstd::reference_wrapper具有转换构造函数,因此,转换后的std::reference_wrapper存储对从std::reference_wrapper获得的对象的引用(通过转换运算符)。

匿名用户

我必须执行一个const_cast来分派到正确的baz::get()函数。

是的。 或std::as_const,或使Bar<;t>可转换为Bar<;constT>

我对const函数成员的理解是,它使this指针指向const,但实际上我并不完全清楚它的含义。。。 所有的数据成员都是‘就像它们是常量’吗?

是的,成员的行为就像是常量

表达式e1->e2完全等同于内置类型的(*e1).e2; 这就是为什么下面的规则只处理E1.E2

在表达式E1.E2中:

如果E2是非静态数据成员:

如果E2是引用类型T&;T&;,则结果是T类型的L值,指定E2引用的对象或函数,否则,如果E1是L值,则结果是指定E1的非静态数据成员的L值,否则(如果E1是xvalue(可从prvalue物化)),则结果是指定E1的非静态数据成员的xvalue。

如果e2不是可变成员,则结果的CV限定条件是e1e2的CV限定条件的并集,否则(如果e2是可变成员),则结果的CV限定条件是e1e2的Volatile限定条件的并集;

-cp首选项

当通过指向const类的指针访问时,其成员变为const

但恒常性只在顶层添加。 如果通过指向const的指针访问int*const member;,则它将成为int*const member;,而不是const int*const member;

引用以类似的方式工作,但是因为引用本身不能是const1,所以它们的类型不会改变。

如果我使用std::reference_wrapper作为代理类,那么它在没有const_cast的情况下工作

这是因为它有一个构造函数,允许从std::reference_wrapper构造std::reference_wrapper

1是的,引用在创建后不能更改为指向其他对象,但形式上它不是常量std::is_const返回引用的false