当const方法是公共的并且非const方法受保护时,为什么C ++不会转换为const?

时间:2012-12-26 18:03:43

标签: c++ const

我用两个get方法创建了一个类,一个是const,一个是非const。 const方法是公共的,因此用户可以查询向量。非const方法受到保护,因此我可以使用它来修改我需要的数据。

但是,当我尝试使用该类并调用get方法时,编译器会抱怨非const方法受到保护。相反,我必须使用const_cast将对象强制转换为const,因此我可以使用公共方法。

有没有办法解决这个问题?为什么编译器不会执行转换,因为有一个公共方法?如果我删除受保护的版本并且只保留const版本,它可以正常工作,因此它会在这种情况下进行转换。转换为const始终是安全的。它正在消除常量问题。

5 个答案:

答案 0 :(得分:6)

成员访问控制是调用成员函数时发生的最后一件事。它发生在名称查找,模板参数推导,重载解析等之后。它最后完成的原因是因为决定更改成员的访问控制不应该突然改变客户端代码的执行。

想象一下在重载解析之前检查了访问权限,并且您在该库中使用了库和某个成员函数。然后,图书馆作者将该功能设为私有。突然,您的代码开始使用不同的重载,并以完全不同的方式运行。库作者可能打算任何使用该函数重载的人都应该停止使用它,但他们并不打算改变每个人的代码。但是,由于标准实际定义,您的代码现在开始使用私有成员时出错,而不是表现不同。

解决方案是简单地更改受保护成员函数的名称,以便不予考虑。

答案 1 :(得分:3)

编译器在决定要调用哪个成员函数之后考虑可访问性。也就是说,受保护和私有功能仍然可见,即使它们不是可访问的

为什么呢?一个原因是,如果您通过重载解析忽略了不可访问的函数,则可以通过更改其可访问性来更改调用的函数。使用当前规则,您只能导致编译代码无法编译,或导致当前无法编译的代码或更改某些内容而不影响代码的含义。您无法更改访问说明符并以静默方式调用其他函数。

作为一个人为的例子,这是一个非常可怕的类接口:

public:
    // Returns the amount of change tendered for this transaction.
    MoneyAmount change() const;

private:
    // Account for a change of currency. Charges standard moneychanger's fee.
    MoneyAmount change(Currency toCurrency = Currency::USD);

如果从重载解析中删除了无法访问的功能,客户端代码可以正常调用change()。如果稍后第二个change(Currency)函数被公开并且第一个被删除,那么该代码会突然默默地调用具有完全不同目的的另一个函数。当前规则阻止访问说明符的更改改变编译程序的行为。

答案 2 :(得分:0)

在C ++中,方法选择(重载分辨率)在考虑公共/私有访问控制之前发生。

答案 3 :(得分:0)

使用受保护的setter方法(或数据成员)代替非const getter方法。

如果你有s.th.没有区别。像

class A {
    SomeType foo_;
protected:
    SomeType& foo() { return foo_; }

public:
    const SomeType& foo() const { return foo_; }
};

class A {
protected:
    SomeType foo_;

public:
    const SomeType& foo() const { return foo_; }
};

答案 4 :(得分:0)

这就是C ++的自然行为,如果调用者代码类的对象是非const,那么非转换,被定义为受保护的。您需要将类的对象定义为const或在类的对象上使用const-cast,这将导致调用方法的const版本。

#include <iostream>
class Foo {
    public:
        const void bar() const { std::cout << " const version called\n";}  
    protected:
        void bar() { std::cout << " non const version called\n";}  
};

int main(int argc, char** argv)
{
    const Foo c;
    c.bar(); // -> work

    Foo c1;
    c1.bar(); // compiler complain -> void Foo::bar() is protected
    const_cast<const Foo&>(c1).bar(); // fine 
}