8

我有一个类,它看起来是这样的:麻烦与常量/非const重载

class ClassA 
{ 
    public: 
    float Get(int num) const; 
    protected: 
    float& Get(int num); 
} 

类之外,我调用get()函数。

float foo = classAInstance.Get(i); 

我希望这个叫公版,而是Visual Studio中出现了错误:

error C2248: 'ClassA::Get' : cannot access protected member declared in class 'ClassA' 

当注释掉保护过载和删除所有引用的代码编译。

为什么编译器会在可访问的成员可用时尝试使用不可访问的成员?有没有一种可以接受的方式来强制编译器选择正确的重载?是否有对成员函数解析规则的引用?

回答

7

确实如此,重载决议发生在可访问性检查之前。标准([over.match])的第13.3节说:

重载决策是选择最佳功能的机制来调用因为是 是调用的参数和一组候选函数表达式的列表可以根据 的调用情况调用。最佳函数的选择标准是参数的个数,参数 与候选函数的参数类型列表匹配的程度,对于非静态成员函数,对象与隐式对象参数匹配程度如何,以及候选函数的某些其他属性。 [注意: 重载解析选择的函数不保证适合上下文。其他 限制,如功能的可访问性,可以使其在调用环境中使用不合格。 - 尾注]

通常的修复方法是给公共和受保护的函数使用不同的名称。


注意,这有时是有用的,例如:

class Blah 
{ 
    const std::string& name_ref; 

    Blah(const char*) = delete; 

public: 
    Blah(const std::string& name) : name_ref(name) {} 

    void do_something_with_name_ref() const; 
}; 

std::string s = "Blam"; 
Blah b(s); // ok 

注意name_ref只会被读取,所以这是适当的,使其const。但const引用可以绑定到临时对象,并将name_ref绑定到临时对象将是一个悬挂引用,导致do_something_with_name_ref()中的未定义行为。

Blah c("Kablooey!"); // would be undefined behavior 
        // the constructor overload makes this a compile error 

私有构造函数重载可防止临时std::string被隐式构造和绑定。

+0

这个例子看起来很危险。给定'string func();'和'Blah b(func())'的表达式将会被编译,并且仍然会导致一个悬挂引用。我的规则是:*从不*保留'const&'参数。你说什么? – 2014-03-07 08:01:05

+0

@MartinBa:当然你也希望'Blah(string &&)= delete;' – 2014-03-07 14:08:27

+0

嗯。然后问题就变成了是否仍然需要'const char'overload。 'char *'参数会绑定到'string const&'版本还是'string &&'版本? :-) – 2014-03-07 14:18:36

5

重载解析首先完成,然后访问检查。

如果你有一个const和一个非常量重载,这可以通过函数被调用的对象的常量来解决。