C++ 类的某些成员只能由基类访问吗?

C++ 类的某些成员只能由基类访问吗?,c++,inheritance,protected,composite,C++,Inheritance,Protected,Composite,我有一个Widget类和一个派生自它的CompositeWidgetCompositeWidget添加子管理行为。Widget构造函数将一个CompositeWidget*参数作为Widget的父项。我需要使用此父指针访问CompositeWidget中的某些功能。例如: Widget::Widget(CompositeWidget* parent) { parent_->AddChild(*this); } 这迫使我创建一个公共方法CompositeWidget::AddChi

我有一个
Widget
类和一个派生自它的
CompositeWidget
CompositeWidget
添加子管理行为。
Widget
构造函数将一个
CompositeWidget*
参数作为Widget的父项。我需要使用此父指针访问
CompositeWidget
中的某些功能。例如:

Widget::Widget(CompositeWidget* parent)
{
    parent_->AddChild(*this);
}
这迫使我创建一个公共方法
CompositeWidget::AddChild
。是否可以将此接口保持为类层次结构的私有接口(有点像反向-
受保护
访问-仅限于基类)?我在思考这样的问题时是否犯了设计错误


编辑:我试图避免友谊(如果在这种情况下可能的话)。

使用
朋友
关键字

class Widget { ... };

class CompositeWidget {
  friend class Widget;
};

但是,您也可以在
小部件
类上插入
virtual
方法
AddChild

使用
friend
关键字

class Widget { ... };

class CompositeWidget {
  friend class Widget;
};
但是,您也可以在
小部件
类上插入
virtual
方法
AddChild

这迫使我创建一个公共方法

不,您可以声明:

friend class Widget;
在CompositeWidget声明中。然而

我是在设计失礼吗

有一个引用派生类的父类方法可能有一点设计缺陷,但我不会说这是绝对错误的

这迫使我创建一个公共方法

不,您可以声明:

friend class Widget;
在CompositeWidget声明中。然而

我是在设计失礼吗


拥有一个引用派生类的父类方法可能有一点设计缺陷,但我不会说这是绝对错误的。

回答你的具体问题:声明
小部件
成为你的
复合Widget
朋友
,并使
AddChild
成为
私有
成员

或者,将子管理移动到
CompositeWidget
。本书在以下章节中对此进行了详细讨论:

该决定涉及安全性和透明度之间的权衡

  • 在类层次结构的根目录定义子管理接口可以提高透明度,因为可以统一处理所有组件。然而,这会让您付出安全代价,因为客户端可能会尝试做一些毫无意义的事情,比如从叶子中添加和删除对象
  • 在复合类< /强>中定义子管理<强>为您提供安全性,因为任何试图从叶中添加或移除对象的方法都会在编译时捕获,如C++中的静态类型语言。但是你会失去透明度,因为树叶和复合材料有不同的界面
在这种模式中,我们强调透明度而非安全性。如果你 选择安全,有时您可能会丢失类型信息并 将构件转换为复合构件的步骤。没有你怎么能做到这一点 求助于不安全类型转换

他们接着给出了一个很长的代码示例,基本上可以归结为这样的设计,
CompositeWidget
包含子管理:

class Widget
{
public:
    //
    virtual Composite* GetComposite() { return 0; }
}

class CompositeWidget: public Widget
{
public:
    void AddChild(Component*); 
    // ...
    virtual Composite* GetComposite() { return this; }   
};

class LeafWidget: public Widget
{
     // no child management here
};
GetComposite
允许您查询小部件以查看它是否是复合部件。你
可以在返回的组合上安全地执行
AddChild

回答您的具体问题:声明
Widget
为您的
CompositeWidget
朋友,并使
AddChild
成为
private
成员

或者,将子管理移动到
CompositeWidget
。本书在以下章节中对此进行了详细讨论:

该决定涉及安全性和透明度之间的权衡

  • 在类层次结构的根目录定义子管理接口可以提高透明度,因为可以统一处理所有组件。然而,这会让您付出安全代价,因为客户端可能会尝试做一些毫无意义的事情,比如从叶子中添加和删除对象
  • 在复合类< /强>中定义子管理<强>为您提供安全性,因为任何试图从叶中添加或移除对象的方法都会在编译时捕获,如C++中的静态类型语言。但是你会失去透明度,因为树叶和复合材料有不同的界面
在这种模式中,我们强调透明度而非安全性。如果你 选择安全,有时您可能会丢失类型信息并 将构件转换为复合构件的步骤。没有你怎么能做到这一点 求助于不安全类型转换

他们接着给出了一个很长的代码示例,基本上可以归结为这样的设计,
CompositeWidget
包含子管理:

class Widget
{
public:
    //
    virtual Composite* GetComposite() { return 0; }
}

class CompositeWidget: public Widget
{
public:
    void AddChild(Component*); 
    // ...
    virtual Composite* GetComposite() { return this; }   
};

class LeafWidget: public Widget
{
     // no child management here
};
GetComposite
允许您查询小部件以查看它是否是复合部件。你
可以在它返回的组合上安全地执行
AddChild

你能让
Widget
成为
CompositeWidget
的朋友吗?最上面的CompositeWidget呢?它将什么指针传递给它的基本小部件c'tor?这似乎是一个糟糕的设计。GoF书籍设计模式在Composite@TemplateRex很遗憾,这本书不是我的。你能发布一个回复,转达其中的一些信息吗?@DanNestor:复合模式也可以在网上找到-你能让<代码>小部件
成为<代码>复合网页
的朋友吗?最上面的复合网页呢?它将什么指针传递给它的基本小部件c'tor?这似乎是一个糟糕的设计。GoF书籍设计模式在Composite@TemplateRex很遗憾,这本书不是我的。你能给我一个回复,转达一些信息吗