C#是否具有私有和受保护继承的概念?

时间:2008-08-28 19:00:58

标签: c# inheritance

C#是否具有私有/受保护继承的概念,如果没有,为什么?

C ++


class Foo : private Bar {
 public:
   ...
 }; 

C#


public abstract NServlet class : private System.Web.UI.Page
{
    // error "type expected"
}

我在.aspx页面中实现了一个“servlet like”概念,我不希望具体类能够看到System.Web.UI.Page基础的内部。

10 个答案:

答案 0 :(得分:17)

C#仅允许公共继承。 C ++允许这三种。公共继承意味着“IS-A”类型的关系,而私有继承意味着“Is-Implemented-In-Terms-Of”这种关系。由于分层(或组合)以一种可以说是简单的方式完成了这一过程,私有继承仅在被保护成员或虚拟函数需要时才使用 - 根据Scott Meyers的Effective C ++,第42项。

我的猜测是,C#的作者并不觉得有必要采用另一种方法来实现另一个类。

答案 1 :(得分:7)

  

不,不。允许这种限制有什么好处?

私有和受保护的继承有利于封装(信息隐藏)。 C ++支持受保护的*继承,尽管它不在Java中。这是我的项目中的一个例子,它将是有用的。

第三方框架中有一个基类**。它有许多设置以及用于操作它们的属性和方法。在分配单个设置时,基类不会进行大量检查,但如果遇到不可接受的组合,它将在以后生成异常。

我正在制作一个子类,其中包含分配这些设置的方法(例如,从文件中分配精心设计的设置)。很高兴拒绝其余代码(在我的子类之外)操纵个别设置并搞砸它们的能力。

那就是说,我认为在C ++中(再次支持私有和受保护的继承),可以将子类强制转换为父类,并可以访问父类的公共成员。 (另请参阅Chris Karcher's post)尽管如此,受保护的继承可以改善信息隐藏。如果B1类的成员需要真正隐藏在其他类C1和C2中,可以通过在C1和C2中创建B1类的受保护变量来安排它。受保护的B1实例将可供C1和C2的儿童使用。当然,这种方法本身并不提供C1和C2之间的多态性。但是,可以通过从公共接口I1继承C1和C2来添加多态(如果需要)。

***为简洁起见,将使用“受保护”而不是“私人和受保护”。

在我的案例中,** National Instruments Measurement Studio。

  • 尼克

答案 2 :(得分:6)

@bdukes: 请注意,您并非真正隐藏该成员。 E.g:

class Base
{
   public void F() {}
}
class Derived : Base
{
   new private void F() {}
}

Base o = new Derived();
o.F();  // works

编辑:但这与C ++中的私有继承完全相同,这就是提问者想要的:)

答案 3 :(得分:5)

您可以通过将类中的同一成员声明为private并使用new关键字来隐藏继承的API,使其不被公开显示。请参阅MSDN中的Hiding through Inheritance

答案 4 :(得分:3)

如果您希望NServlet类对页面一无所知,您应该考虑使用适配器模式。编写一个将托管NServlet类实例的页面。根据您正在做的事情,您可以编写各种类,只知道基类NServlet,而不必使用asp.net页面成员污染您的API。

答案 5 :(得分:1)

不,仅限公共继承。

答案 6 :(得分:1)

您可能想要一个与NServlet实现相关联的ServletContainer类。在我的书中,不允许私有/受保护的继承并不是一个大问题,并且使语言不那么混乱 - 使用LINQ等我们已经有足够的东西要记住了。

答案 7 :(得分:1)

我知道这是一个老问题,但我在编写C#时遇到过这个问题几次,我想知道......为什么不使用界面?

当您创建第三方框架类的子类时,还要实现公共接口。然后定义该接口以仅包含您希望客户端访问的方法。然后,当客户端请求该类的实例时,请为它们提供该接口的实例。

这似乎是C#接受的做这类事情的方式。

我第一次这样做是因为我意识到C#标准库没有字典的只读变体。我想提供对字典的访问,但不想让客户端能够更改字典中的项目。所以我定义了一个“类DictionaryEx< K,V,IV>:Dictionary< K,V>,IReadOnlyDictionary< K,IV>其中V:IV”,其中K是键类型,V是实数值类型,IV是阻止更改的V类型接口。 DictionaryEx的实施大多是直截了当的;唯一困难的部分是创建一个ReadOnlyEnumerator类,但即使这样也不需要很长时间。

我可以看到这种方法的唯一缺点是客户端是否尝试将您的公共接口动态转换为相关的子类。要阻止这种情况,请将您的课程内部化。如果您的客户端将您的公共接口转换为原始基类,我认为他们很清楚他们将自己的生命掌握在自己手中。 : - )

答案 8 :(得分:1)

第一个解决方案:

受保护的内部在同一个程序集中充当public并在其他程序集上受到保护。

您需要更改不通过继承公开的类的每个成员的访问修饰符。

虽然此解决方案需要并强制继承类以供另一个程序集使用,但这有点限制。因此,只有通过继承使用的选择是由不知情的父母选择的...通常孩子们更了解建筑......

不是一个完美的解决方案,但可能是一个更好的替代添加界面来隐藏方法,并且仍然可以通过子类隐藏使用父方法,因为你可能不容易能够强制使用界面。

<强>问题:

受保护隐私访问修饰符无法用于实施 接口的方法即可。这意味着受保护的内部解决方案不能用于接口实现的方法。这是一个很大的限制。

最终解决方案:

我回到界面解决方案隐藏方法

它的问题是能够强制使用界面,以便隐藏隐藏的成员,然后绝对避免错误。

强制仅使用界面,只需使构造函数受保护添加构造的静态方法(我将其命名为New)。这个静态New方法实际上是一个工厂函数,返回接口。所以代码的其余部分只能使用接口!

答案 9 :(得分:-2)

不,不。允许这种限制有什么好处?

相关问题