2

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

作为一个具体的例子,看看下面的代码,请告诉我如何避免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
    }
}

编辑:我修改了我的示例,所以我没有(人们认为 Init 总是可以在构造函数中调用)ComputeSizeInit

4

2 回答 2

2

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

这里的根本问题是您希望某些特权类(“复合”)能够调用基类声明的外部类(“组件”)的方法,该方法仅用于在其自己的实现中使用派生类。

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

于 2013-08-07T13:00:22.533 回答
1

Initialise()在调用 Init 的基类中创建一个非虚函数

例如:

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

于 2013-08-07T12:55:34.240 回答