我正在尝试正确封装一个 A 类,它只能由 B 类操作。
但是,我想从 B 类继承。
拥有朋友 B 是行不通的——友谊不是遗传的。
完成我想要的事情的普遍接受的方式是什么,或者我犯了错误?
为了给你更多的色彩,A 类代表一个复杂系统的状态。它只能由 B 修改,这些操作可用于更改 A 类的状态。
我正在尝试正确封装一个 A 类,它只能由 B 类操作。
但是,我想从 B 类继承。
拥有朋友 B 是行不通的——友谊不是遗传的。
完成我想要的事情的普遍接受的方式是什么,或者我犯了错误?
为了给你更多的色彩,A 类代表一个复杂系统的状态。它只能由 B 修改,这些操作可用于更改 A 类的状态。
听起来您可能需要重新设计;您的 A 类代表一个州,但您的 B 类代表一组动作。那里有关系,但不是继承关系。我建议作文;据我所知,你想要更多的 HASA 关系而不是 ISA 关系。
如果我对您的理解正确,您希望拥有 B及其衍生产品以访问 A 类的内部实现,是吗?
不幸的是,C++ 没有像 C# 和 Java 这样的语言所拥有的“内部”保护级别的概念。
您可以考虑使用私有实现范例(pimpl) - 也称为不透明指针,以使用公共访问级别公开系统内的功能,而 A 和 B 的使用者不会看到。
我假设您想允许 B 的后代直接访问 A?如果 A 和 B 紧密耦合,则可以使 A 在 B 本身内成为受保护的类定义,而不是成为独立的定义。例如
class B
{
protected:
class A
{
};
};
另一个想法是在 B 上创建受保护的方法,将它们的操作委托给 AEG
class A
{
friend class B;
private:
void DoSomething();
};
class B
{
protected:
void DoSomething(A& a) { a.DoSomething(); }
};
最直接的方法就是让 B 包含一个 A:
B类{保护:A a_; };
然后,您可以编写一个从 B 继承并能够操作 A 的类 C。如果 C 不应该对 A 做任意事情,那么将 A 在 B 中设为私有,并在 B 中提供 C 可以的受保护方法用来对 A 做批准的事情,像这样:
B类{私人:A a_; 受保护:无效doSomethingToA();};
保持一切不变,最简单的做法是向 B 添加受保护的方法,以访问它需要的 A 的等效功能。这打开了对 B 的子类的封装。
包含是要走的路(B 类包含 A 类型的私有成员),除非 B 需要覆盖 A 中的一些虚拟,在这种情况下,私有继承是最接近的事情。
我不明白你为什么要继承。将 A 中的所有内容设为私有并设为好友 B。然后 B 拥有 A 的成员,它可以自由操作。
你描述它的方式听起来更像是组合而不是继承。例如
class ComplexMachine {
public:
setState(int state);
};
class Operator {
public:
Operator(ComplexMachine & m) :_m(m) {};
void drive() { _m->setState(1); }
void turn() { _m->setState(2); }
void stop() { _m->setState(0); }
private:
ComplexMachine _m;
};
class SmoothOperator : public Operator { }
使用您提供的信息:
B 类应该负责保留 A 类的不变量,而 B 类应该是操作 A 的唯一方法。任何客户端(派生类或调用者)都不需要知道 A 的存在。
(从设计 POV 来看,A 甚至不需要存在,但我已经遇到了足够多的实际原因导致这种分离,所以我不会反对你;))
这可能需要编写大量样板代码,或者需要一些接口技巧。例如,如果允许客户端使用类 A 来查询信息但不能修改它,B 可以将 const & 分发给聚合的 A。使用支持 __declspec(property) 或类似的编译器,可以减轻语法上的痛苦。
根据我从您的问题中了解到的情况,您将需要一些polymorphism。您需要一个抽象类 A,而类 B 继承类 A。此外,protected关键字允许继承的类访问某些信息,同时拒绝访问其他任何信息。这是一个小例子:
// dynamic allocation and polymorphism
#include <iostream>
using namespace std;
class CPolygon {
protected:
int width, height;
public:
void set_values (int a, int b)
{ width=a; height=b; }
virtual int area (void) =0;
void printarea (void)
{ cout << this->area() << endl; }
};
class CRectangle: public CPolygon {
public:
int area (void)
{ return (width * height); }
};
class CTriangle: public CPolygon {
public:
int area (void)
{ return (width * height / 2); }
};
int main () {
CPolygon * ppoly1 = new CRectangle;
CPolygon * ppoly2 = new CTriangle;
ppoly1->set_values (4,5);
ppoly2->set_values (4,5);
ppoly1->printarea();
ppoly2->printarea();
delete ppoly1;
delete ppoly2;
return 0;
}
取自cplusplus.com的代码(也包含有关多态性和抽象类的信息)。
如果您想确保只有 B 对 A 进行操作,请将 A 的实例设为私有并将 B 的受保护接口公开给其后代。
class A
{
public:
void foo() {}
};
class B
{
private:
A a;
protected:
void CallAFoo() { a.foo() };
};
class C : public B
{
void goo() { CallAFoo(); }
};