如何防止基 class 的受保护成员在子 class 的第二层仍然被访问?
How do you prevent protected members of the base class from still being accessed in the second level of the subclass?
一个例子来说明我的问题:
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
class 中访问 Base
的受保护成员,尽管 Base
的受保护成员只能在 DerivedClass1
中更改.通过将Base
中的变量继承到DerivedClass1
中,将形成一个class,DerivedClass2
不得对其进行操作。在 C# 中,这可以通过 private protected
关键字实现,但如何在 C++ 中处理它?
您可以将数据成员声明为 private
并使用 friend
声明明确指定哪个 类 可以访问它:
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
}
};
受保护的后果是什么?
protected
的理念就是允许所有派生的 classes 访问这些成员。
虽然这是一个非常灵活的语言特性,但它在封装中造成了严重的弱点,这会鼓励打破 Liskov Substitution Principle(更准确地说是历史约束,因为派生的 class 可能会改变基础对象的状态而不经过基础 class 原语)。
如何避免它的弊端?
如果你想要更强的封装和限制访问,你需要去private
。这确保只能使用 public 接口访问基 class 的内部状态。 (请注意,虽然它确保了历史约束,但它本身并不能保证 LSP)。结果是派生 class 无法访问。不是一开始推导,也不是后来。
你需要私人保护吗?
你想要的,是一种介于两者之间的:弱封装,但不是太弱。这在 C++ 中不存在。而且我不确定它会加强你的设计。
但如果您在特殊情况下需要此限制,则可以使用名称查找来解决:
class DerivedClass1 : public Base
{
private:
using Base::x;
// In DerivedClass1 you can still use x.
};
// But it will fail to compile in Derived2
但我个人不建议走这条路。它很容易出错(您可能会忘记派生的一个兄弟中的 using
)。编译器错误消息可能具有误导性。不管怎样,private 会产生更健壮的设计。
继承一个'private'基数:
class DerivedClass1 : private Base
{
};
编辑:通过public公开public或Base中的受保护成员或DerivedClass1中的受保护成员。 DerivedClass1 可以完全控制继承自 DerivedClass1[= 的 类 可以访问和不可以访问的 Base 成员23=].
这是否是一个好的解决方案取决于 Base 的复杂性。
一个例子来说明我的问题:
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
class 中访问 Base
的受保护成员,尽管 Base
的受保护成员只能在 DerivedClass1
中更改.通过将Base
中的变量继承到DerivedClass1
中,将形成一个class,DerivedClass2
不得对其进行操作。在 C# 中,这可以通过 private protected
关键字实现,但如何在 C++ 中处理它?
您可以将数据成员声明为 private
并使用 friend
声明明确指定哪个 类 可以访问它:
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
}
};
受保护的后果是什么?
protected
的理念就是允许所有派生的 classes 访问这些成员。
虽然这是一个非常灵活的语言特性,但它在封装中造成了严重的弱点,这会鼓励打破 Liskov Substitution Principle(更准确地说是历史约束,因为派生的 class 可能会改变基础对象的状态而不经过基础 class 原语)。
如何避免它的弊端?
如果你想要更强的封装和限制访问,你需要去private
。这确保只能使用 public 接口访问基 class 的内部状态。 (请注意,虽然它确保了历史约束,但它本身并不能保证 LSP)。结果是派生 class 无法访问。不是一开始推导,也不是后来。
你需要私人保护吗?
你想要的,是一种介于两者之间的:弱封装,但不是太弱。这在 C++ 中不存在。而且我不确定它会加强你的设计。
但如果您在特殊情况下需要此限制,则可以使用名称查找来解决:
class DerivedClass1 : public Base
{
private:
using Base::x;
// In DerivedClass1 you can still use x.
};
// But it will fail to compile in Derived2
但我个人不建议走这条路。它很容易出错(您可能会忘记派生的一个兄弟中的 using
)。编译器错误消息可能具有误导性。不管怎样,private 会产生更健壮的设计。
继承一个'private'基数:
class DerivedClass1 : private Base
{
};
编辑:通过public公开public或Base中的受保护成员或DerivedClass1中的受保护成员。 DerivedClass1 可以完全控制继承自 DerivedClass1[= 的 类 可以访问和不可以访问的 Base 成员23=].
这是否是一个好的解决方案取决于 Base 的复杂性。