C ++和C#中的复合模式 - 受保护的虚拟方法

时间:2013-08-07 12:42:13

标签: c# c++ oop design-patterns composite

如何在“Component”类中添加受保护的虚拟方法,以便可以从“Composite”调用它?

作为具体示例,请查看下面的代码,请告诉我如何避免DxCompositeShape.ComputeSize中的编译器错误。

abstract class DxShape // this is the Component
{
    public abstract void Paint();
    protected abstract void ComputeSize();
}

class DxCompositeShape : DxShape // this is the Composite
{
    public readonly IList<DxShape> Shapes = new List<DxShape>();

    public override void Paint()
    {
        this.ComputeSize();
    }

    protected override void ComputeSize()
    {
        foreach (DxShape sh in Shapes)
        {
            sh.ComputeSize(); // compiler error CS1540
        }
        // and some other logic here
    }
}
编辑:我修改了我的示例,所以我有ComputeSize而不是Init(人们假设始终可以在构造函数中调用Init)。

2 个答案:

答案 0 :(得分:2)

你做不到。只有在编译器可以看到有问题的对象与当前对象的类型相同时,才能调用其他对象的受保护成员。基本上,“受保护”意味着“派生类可以在自己的类中使用此成员。

这里的根本问题是你希望一些特权类(“复合”)能够调用外部类(“组件”)的方法,基类声明的方法只是在他们自己的实现中使用派生类

如果所有复合材料都在同一个包中,您可能希望将Init设为内部。或者可以创建所有组合继承的组件的子类,并使此特定类特权在所有组件上调用Init。在C ++中,你会用朋友声明做这样的事情。在C#中,谨慎使用内部访问可能是正确的解决方案。

答案 1 :(得分:1)

在调用Init

的基类中创建非虚函数Initialise()

例如:

abstract class DxShape
{
    protected void Initialise()
    {
        Init();
    }
    protected abstract void Init();
    //...
}

正如下面的评论所指出的,Initialise必须是公共的或静态的(仅在C#中),它可能在C ++中保持受保护。 在C ++中,您可以将Init设为私有,只能通过调用Initialise来访问它。请参阅非虚拟接口http://en.wikipedia.org/wiki/Non-virtual_interface_pattern