C++ 为什么我可以从常量方法调用非常量成员函数指针?

C++ 为什么我可以从常量方法调用非常量成员函数指针?,c++,C++,一位同事询问了一些类似这样的代码,这些代码最初包含模板 我已经删除了模板,但核心问题仍然存在:为什么这个编译可以 #include <iostream> class X { public: void foo() { std::cout << "Here\n"; } }; typedef void (X::*XFUNC)() ; class CX { public: explicit CX(X& t, XFUNC xF) : object(t

一位同事询问了一些类似这样的代码,这些代码最初包含模板

我已经删除了模板,但核心问题仍然存在:为什么这个编译可以

#include <iostream>

class X
{
public:
     void foo() { std::cout << "Here\n"; }
};

typedef void (X::*XFUNC)() ;

class CX
{
public:
    explicit CX(X& t, XFUNC xF) : object(t), F(xF) {}      
    void execute() const { (object.*F)(); }
private:
    X& object;
    XFUNC F;
}; 

int main(int argc, char* argv[])
{   
    X x; 
    const CX cx(x,&X::foo);
    cx.execute();
    return 0;
}
#包括
X类
{
公众:

void foo(){std::cout在此上下文中,对象
是对
X
的引用,而不是对常量
X
的引用。
const
限定符将应用于成员(即引用,但引用不能是
const
),而不是被引用的对象

如果将类定义更改为不使用引用:

// ...
private:
    X object;
// ...

您得到了预期的错误。
execute()的
常量
只影响类的
this
指针。它使
this
的类型成为
常量T*
,而不仅仅是
T*
。但这不是一个“深”常量-它只意味着成员本身无法更改,但它们指向或引用的任何内容仍然可以更改。您的
对象
成员已经可以不能更改,因为引用不能重新定位以指向任何其他内容。类似地,您没有更改
F
成员,只是将其作为成员函数指针取消引用。因此,这是允许的,可以

您创建CX const实例的事实并没有改变任何东西:同样,这指的是不允许修改直接成员,但它们指向的任何对象仍然可以修改。您仍然可以在const对象上调用const成员函数,因此不允许修改

举例说明:

class MyClass
{
public:
    /* ... */

    int* p;

    void f() const
    {
        // member p becomes: int* const p
        *p = 5;   // not changing p itself, only the thing it points to - allowed
        p = NULL; // changing content of p in const function - not allowed
    }
};

类X的实例
对象
不是常量。它仅由常量对象引用。常量递归地应用于子对象,而不是引用的对象


通过替代逻辑, const 方法不能修改任何东西,这被称为“纯函数”,在当前标准C++中不存在一个概念。

< p>您在<代码>对象< /代码>上调用<代码> Foo<代码>,而不是在<代码> < < /C> > < /P>
由于
对象
被声明为
X&
,在常数CX中,它实际上是
X&const
(这与
常数X&
不同)允许您对其调用非常量方法。

一种有用的思考方式可能是,您的X对象根本不是CX的成员。

但是,对于
const
-方法,您应该只能对成员对象调用
const
-方法,不是吗?成员是引用,而不是引用的对象。这很重要我要注意的是,基本上可以将
T&
视为
T*const
。无论如何,我同意
const
的浅层传播是奇怪的,但是默认情况下我们也有浅层副本……你可以这样想,但它是或不是并不重要。该类可以有一个X实例(
对象
)作为一个成员和一个引用成员来引用它。然后你会发现你不能做
(object.*F();
,但仍然可以做
(reference.*F();
,即使它引用了与CX成员完全相同的东西。我觉得你应该提到“X&const”在语言中是非感官的,因为没有“引用重新绑定”这样的东西。