如何防止仍然在子类的第二级访问基类的受保护成员?

问题描述 投票:2回答:3

举例说明我的问题:

class Base
{
protected:
    int x{ 0 };
};

class DerivedClass1 : public Base
{
};

class DerivedClass2 : public DerivedClass1
{
public:
    int getX() const
    {
        return x;
    }
};

int main()
{
    DerivedClass2 d2{};
    int x{ d2.getX() };
    return 0;
}

我可以访问Base类中受保护的DerivedClass2成员,尽管Base的受保护成员只能在DerivedClass1中更改。通过将Base中的变量继承到DerivedClass1,将形成一个类,DerivedClass2不得操纵它。在C#中,这可以使用private protected关键字,但是如何在C ++中处理它?

c++ class oop inheritance protected
3个回答
4
投票

What are the consequences of protected?

protected的想法是允许所有派生类访问这些成员。

虽然这是一个非常灵活的语言特性,但它在封装中造成了严重的弱点,这鼓励打破Liskov Substitution Principle(更准确地说是历史约束,因为派生类可以改变基础对象的状态而不通过基类原语) 。

How to avoid its drawbacks ?

如果你想要更强的封装和限制访问,你需要去private。这确保只能使用公共接口访问基类的内部状态。 (请注意,虽然它确保了历史约束,但它本身并不保证LSP)。结果是没有派生类获得访问权限。不是最初的推导,也不是后来的推导。

Do you need private protected ?

你想要什么,是一种中间:弱封装,但不是太弱。这在C ++中不存在。而且我不确定它会加强你的设计。

但是如果你在特殊情况下需要这个限制,可以有一个解决方法,玩名称查找:

class DerivedClass1 : public Base
{
private:
    using Base::x; 
// In DerivedClass1 you can still use x.
};

// But it will fail to compile in Derived2

Online demo

但我个人不建议这样做。这很容易出错(你可能会忘记一个兄弟姐妹中的using)。编译器错误消息可能会产生误导。无论如何,私人产生更强大的设计。


1
投票

您可以将数据成员声明为private并使用friend-declarations显式指定哪些类可以访问它:

class Base
{
    friend class DerivedClass1;
private:
    int x = 0;
};

class DerivedClass1 : public Base
{
    void test() {
        cout << x;  // OK: DerivedClass1 is a friend of Base
    }
};

class DerivedClass2 : public DerivedClass1
{
public:
    int getX() const
    {
        return x;  // ERROR: x is a private member
    }
};

0
投票

继承'私人'基地​​:

class DerivedClass1 : private Base
{

};

编辑:通过DerivedClass1中的公共成员或受保护成员公开Base中的公共成员或受保护成员。然后,DerivedClass1可以完全控制从DerivedClass1继承的类可以访问和不能访问的Base成员。

这是否是一个好的解决方案取决于Base的复杂性。

© www.soinside.com 2019 - 2024. All rights reserved.