31

为了我的目的,我尝试包装类似于 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 函数,因此调用的 operator -> 应该是 const 的。当我注释掉非常量时,它编译时没有错误,所以这是可能的。然而我的终端打印:

“非常量数据指针”

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

4

4 回答 4

34

如果您有两个仅在const-ness 上有所不同的重载,则编译器会根据是否存在来解析*this调用const。在您的示例代码中,testis not ,因此调用const了非重载。const

如果你这样做:

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

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

于 2011-09-02T17:25:59.580 回答
12

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

编辑:顺便说一句,你怀疑 99.9% 的时间你认为你发现了一个编译器错误,你应该重新审视你的代码,因为可能有一些奇怪的怪癖,编译器实际上是遵循标准的。

于 2011-09-02T17:28:52.060 回答
2

是否Data::x是一个常数函数并不重要。被调用的操作符属于container<Data>类而不是Data类,它的实例不是常量,所以调用非常量操作符。如果只有常量运算符可用或者类的实例本身是常量,那么常量运算符就会被调用。

于 2011-09-02T17:28:05.537 回答
0

testType不是 const 对象。

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

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

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

于 2011-09-02T17:27:44.973 回答