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

Posted

技术标签:

【中文标题】如何防止基类的受保护成员仍然在子类的第二级被访问?【英文标题】:How do you prevent protected members of the base class from still being accessed in the second level of the subclass? 【发布时间】:2019-07-19 09:54:25 【问题描述】:

一个例子来说明我的问题:

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;

我可以在DerivedClass2 类中访问Base 的受保护成员,尽管Base 的受保护成员只能在DerivedClass1 中更改。通过将Base 中的变量继承到DerivedClass1,应形成一个类,DerivedClass2 不得对其进行操作。在 C# 中,这可以通过 private protected 关键字来实现,但是在 C++ 中如何处理呢?

【问题讨论】:

受保护的数据几乎总是一个坏主意。简单地说,不要使用它。 感谢您的快速回复 - 嗯好的。 FWIW,C# private protected 访问级别也不是你想要的。 【参考方案1】:

受保护的后果是什么?

protected 的理念就是允许所有派生类访问这些成员。

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

如何避免它的弊端?

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

你需要私人保护吗?

你想要的是一种介于两者之间的:弱封装,但不能太弱。这在 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)。编译器错误消息可能具有误导性。无论如何,私人会产生更强大的设计。

【讨论】:

【参考方案2】:

您可以将数据成员声明为 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
    
;

【讨论】:

是的,谢谢。当然,这将是一个折中的解决方案。 确实,这也是一种可能的解决方法。它的主要缺点是它强制BaseDerived 之间存在强耦合,特别是Base 需要了解其所有潜在的一阶导数。不是真的OCP-friendly ;-)【参考方案3】:

继承一个“私有”基础:

class DerivedClass1 : private Base


;

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

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

【讨论】:

这当然是一个解决方案,但这仅在base 类没有公共成员时才有效。谢谢:) 真;这些成员需要通过 DerivedClass1 中的公共或受保护方法公开。

以上是关于如何防止基类的受保护成员仍然在子类的第二级被访问?的主要内容,如果未能解决你的问题,请参考以下文章

访问基类的受保护成员

C++ - 访问基类的受保护/私有成员

C++ 派生模板类:访问实例的受保护成员

Java中的间接子类无法访问的超类中的受保护成员

在父类的子类中访问静态类的受保护成员

访问另一个子类中基类的受保护成员