13

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

但是,当我尝试使用该类并调用 get 方法时,编译器会抱怨非常量方法受到保护。相反,我必须使用 const_cast 将对象强制转换为 const,这样我才能获得公共方法。

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

4

5 回答 5

7

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

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

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

于 2012-12-26T18:10:32.513 回答
5

编译器在决定要调用哪个成员函数后考虑可访问性。也就是说,protected 和 private 函数仍然可见,即使它们不可访问

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

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

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)公开第二个函数并删除第一个函数,该代码会突然默默地调用另一个具有完全不同目的的函数。当前规则防止访问说明符的更改改变编译程序的行为。

于 2012-12-26T18:11:58.527 回答
0

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

于 2012-12-26T18:07:54.100 回答
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_; }
};
于 2012-12-26T18:09:43.787 回答
0

这就是 C++ 的本质行为,如果调用者代码类的对象是非常量的,那么就是非转换,这被定义为受保护的。您需要将类的对象定义为 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 
}
于 2012-12-26T19:03:47.917 回答