为什么调用非常量成员函数而不是常量成员函数?

问题描述 投票:0回答:4

出于我的目的,我尝试包装类似于 Qt 共享数据指针的东西,经过测试,我发现当应调用 const 函数时,会选择其非 const 版本。

我正在使用 C++0x 选项进行编译,这是一个最小的代码:

struct Data {
    int x() const {
        return 1;
    }
};

template <class T>
struct container
{
    container() {
        ptr = new T();
    }


    T & operator*() {
        puts("non const data ptr");
        return *ptr;
    }

    T * operator->() {
        puts("non const data ptr");
        return ptr;
    }

    const T & operator*() const {
        puts("const data ptr");
        return *ptr;
    }

    const T * operator->() const {
        puts("const data ptr");
        return ptr;
    }

    T* ptr;
};

typedef container<Data> testType;

void testing() {
    testType test;
    test->x();
}

如您所见,Data.x 是一个 const 函数,因此调用的运算符 -> 应该是 const 函数。当我注释掉非常量时,它编译时没有错误,所以这是可能的。但我的终端打印:

“非常量数据指针”

这是一个 GCC 错误(我有 4.5.2),还是我遗漏了什么?

c++ constants operator-overloading overload-resolution function-qualifier
4个回答
37
投票

如果您有两个仅在

const
性质上有所不同的重载,则编译器将根据
*this
是否为
const
来解析调用。在您的示例代码中,
test
不是
const
,因此调用非
const
重载。

如果您这样做:

testType test;
const testType &test2 = test;
test2->x();

您应该看到另一个重载被调用,因为

test2
const


15
投票

test
是一个非常量对象,因此编译器会找到最佳匹配:非常量版本。不过,您可以使用
static_cast
应用常量:
static_cast<const testType&>(test)->x();

编辑:顺便说一句,正如您怀疑 99.9% 的时间您认为自己发现了编译器错误一样,您应该重新访问您的代码,因为可能存在一些奇怪的怪癖,而编译器实际上遵循标准。


2
投票

Data::x
是否是常数函数并不重要。被调用的运算符属于
container<Data>
类而不是
Data
类,并且其实例不是常量,因此调用非常量运算符。如果只有常量运算符可用或者类的实例本身就是常量,则将调用常量运算符。


1
投票

但是

testType
不是 const 对象。

因此它将调用其成员的非常量版本。
如果这些方法具有完全相同的参数,则必须选择调用哪个版本(因此它使用 this 参数(隐藏的参数))。在这种情况下,这不是 const,因此您将获得非常量方法。

testType const test2;
test2->x();  // This will call the const version

这不会影响对 x() 的调用,因为您可以在非 const 对象上调用 const 方法。

© www.soinside.com 2019 - 2024. All rights reserved.