简体   繁体   English

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

[英]Composite pattern in C++ and C# - protected virtual methods

How can I add a protected virtual method in the "Component" class, so that it can be called from the "Composite"? 如何在“ Component”类中添加受保护的虚拟方法,以便可以从“ Composite”中调用它?

As an concrete example, look at the code below, and please tell me how to avoid the compiler error in DxCompositeShape.ComputeSize . 作为一个具体的示例,请看下面的代码,请告诉我如何避免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
    }
}

EDIT: I modified my sample, so I have ComputeSize instead of Init (people assume that Init can always be called in a constructor). 编辑:我修改了我的示例,所以我有ComputeSize而不是Init (人们认为Init总是可以在构造函数中调用)。

You can't. 你不能 A protected member of a different object can only be invoked if the compiler can see that the object in question is of the same type as your current object. 仅当编译器看到所讨论的对象与当前对象具有相同的类型时,才可以调用其他对象的受保护成员。 Basically, "protected" means "Derived classes can use this member in their own class. 基本上,“受保护”是指“派生类可以在自己的类中使用此成员。

The underlying issue here is that you want some privileged classes ("composites") to be able to call a method of foreign classes ("components") that the base class declares is only for use of derived classes in their own implementation. 这里的根本问题是,您希望某些特权类(“复合”)能够调用基类声明的仅用于派生类在其自己的实现中的外部类(“组件”)的方法。

You might want to make Init internal, if all composites are in the same package. 如果所有组合都在同一程序包中,则可能需要将Init设为内部。 Or maybe make a subclass of the component that all composites inherit, and make this particular class privileged to call Init on all components. 或者,可以使所有复合材料都继承的组件成为子类,并使该特定类有特权在所有组件上调用Init In C++ you would do such a thing with friend declarations. 在C ++中,您可以通过朋友声明来做这样的事情。 In C#, careful use of internal access is probably the right solution. 在C#中,谨慎使用内部访问可能是正确的解决方案。

Create a non-virtual function Initialise() in the base class that calls Init 在调用Init的基类中创建一个非虚拟函数Initialise()

eg: 例如:

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

As pointed out in the comments below, Initialise must be made either public or static (only in C#), it may remain protected in C++. 如以下注释中所指出的, Initialise必须公开或静态(仅在C#中),它可以在C ++中保持受保护的状态。 In C++ you could then make Init private and only access it via calls to Initialise . 然后,在C ++中,您可以将Init设为私有,并且只能通过调用Initialise来访问它。 See non-virtual interface http://en.wikipedia.org/wiki/Non-virtual_interface_pattern 参见非虚拟界面http://en.wikipedia.org/wiki/Non-virtual_interface_pattern

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM