6

我遇到了一个我不明白的编译问题,我已经简化了一点,以便在下面解释。

基本上,它涉及有 2 个不同的 getter(一个 const 和一个非 const 的),它们分别返回一个具有 const 的容器(在这个例子中是一个映射),分别是 non-const value_type。

令我困惑的是,在下面的示例中,编译器似乎无法在非常量对象上使用 const getter:

#include "stdafx.h"
#include <utility>
#include <map>

class TestObject
{
public:

    TestObject() {}
    virtual ~TestObject() {}
};

typedef std::pair<const TestObject*, const TestObject*> ConstTestObjectPair;
typedef std::pair<TestObject*, TestObject*> TestObjectPair;

class Test
{
    TestObject* m_pObject;

public:

    Test() {m_pObject = new TestObject();}
    virtual ~Test() {delete m_pObject;}

    std::map<unsigned, ConstTestObjectPair> GetObject() const
    {
        std::map<unsigned, ConstTestObjectPair> map;
        map.insert(std::make_pair(0, std::make_pair(m_pObject, m_pObject)));
        return map;
    }

    std::map<unsigned, TestObjectPair> GetObject()
    {
        std::map<unsigned, TestObjectPair> map;
        map.insert(std::make_pair(0, std::make_pair(m_pObject, m_pObject)));
        return map;
    }
};

int _tmain(int argc, _TCHAR* argv[])
{
    Test* pTest = new Test();
    const Test* pConstTest = pTest;

    std::map<unsigned, ConstTestObjectPair> CTO = pTest->GetObject(); // Not compiling, I don't get why!!!
    CTO = pConstTest->GetObject();

    std::map<unsigned, TestObjectPair> TO = pTest->GetObject();
    //TO = pConstTest->GetObject(); // Not working, this is expected

    return 0;
}

我尝试使用 VS2010 和 gcc,但都不接受编译此代码。这是VS2010返回的编译错误:

1>c:\test.cpp(48): error C2440: 'initializing' : cannot convert from 'std::map<_Kty,_Ty>' to 'std::map<_Kty,_Ty>'
1>          with
1>          [
1>              _Kty=unsigned int,
1>              _Ty=TestObjectPair
1>          ]
1>          and
1>          [
1>              _Kty=unsigned int,
1>              _Ty=ConstTestObjectPair
1>          ]
1>          No constructor could take the source type, or constructor overload resolution was ambiguous

有人可以解释一下为什么编译器无法在非常量对象上找到/使用正确的原型吗?

非常感谢!

4

4 回答 4

5

如果你真的很好奇,请查看 C++03 标准的第 13.3.3 节,其中描述了如何确定“最佳可行函数”。以下是一些要点:

最佳函数的选择标准是参数的数量、参数与候选函数参数类型的匹配程度、对象与隐含对象参数的匹配程度(对于非静态成员函数)以及候选函数。[注意:重载决议选择的函数不能保证适合上下文。其他限制,例如函数的可访问性,可能使其在调用上下文中的使用格式错误。]

然后:

如果恰好有一个可行函数比所有其他可行函数更好,那么它就是重载决议选择的那个

请注意,此标准中未提及函数的返回类型。所以选择非常量方法是最有效的,因为它的“隐含对象参数”(本质上是“this”指针)是非常量的。这一切都发生在检测到与返回类型的冲突之前。

为了解决这个问题,我会:

  • 更改您的设计,这样ConstTestObjectPair就不需要了,您可以使用const TestObjectPair(首选解决方案)
  • 在需要时将非 const 对象转换为 const 对象
于 2013-06-04T16:12:04.020 回答
4

令我困惑的是,在下面的示例中,编译器似乎无法在非常量对象上使用 const getter

这不是“无法”,而是需要选择另一个。

使用传递的实际参数选择重载。对于成员函数,包括用于this. 对于 T*,选择了非常量重载,如果您想要另一个,则必须通过强制转换或其他方式使用 const T*。

实际上,认为返回类型将以某种方式使用并且返回您要在表达式中使用的函数被选中是一个常见的错误。事实并非如此。

于 2013-06-04T16:03:31.757 回答
1

问题很简单。是pTest指向非 const类型对象的指针。因此在调用中选择了非常量成员函数,即TestpTest->GetObject()

std::map<unsigned, TestObjectPair> GetObject()

如您所见,此函数返回一个 type 的值std::map<unsigned, TestObjectPair>。但是然后您尝试初始化CTO类型的变量

std::map<unsigned, ConstTestObjectPair>

有了这个值。为此,编译器需要将返回值转换为此类型。但是没有转换构造函数可以做到这一点。这就是编译器错误告诉你的。

于 2013-06-04T16:29:00.533 回答
0

C++ 编译器将选择显式覆盖的方法,因此这里 pTest 是一个非常量可行且 pConstTest 是 const 。

Test* pTest = new Test();
const Test* pConstTest = pTest;

pTest->GetObject 将选择非常量 GetObject:

std::map<unsigned, TestObjectPair> GetObject()
{
    std::map<unsigned, TestObjectPair> map;
    map.insert(std::make_pair(0, std::make_pair(m_pObject, m_pObject)));
    return map;
}

pConstTest->GetObject() 将选择 const GetObject:

std::map<unsigned, ConstTestObjectPair> GetObject() const
{
    std::map<unsigned, ConstTestObjectPair> map;
    map.insert(std::make_pair(0, std::make_pair(m_pObject, m_pObject)));
    return map;
}

第一个错误发生在您分配返回的

std::map<unsigned, TestObjectPair> value 

到一个

std::map<unsigned, ConstTestObjectPair> viable
于 2013-06-04T16:26:13.183 回答