我不是C ++的人,但是我不得不考虑这一点。为什么在C ++中可能有多重继承,但在C#中却没有?(我知道钻石的问题,但这不是我要问的)。C ++如何解决从多个基类继承的相同方法签名的歧义?为什么同一个设计没有合并到C#中?
我不是C ++的人,但是我不得不考虑这一点。为什么在C ++中可能有多重继承,但在C#中却没有?(我知道钻石的问题,但这不是我要问的)。C ++如何解决从多个基类继承的相同方法签名的歧义?为什么同一个设计没有合并到C#中?
Answers:
为什么在C ++中可能有多重继承,但在C#中却没有?
我认为(没有硬性参考),他们希望在Java中限制该语言的表达能力,以使该语言更易于学习,因为使用多重继承的代码出于自身的利益而往往过于复杂。而且由于完全多重继承的实现要复杂得多,因此它也大大简化了虚拟机(多重继承与垃圾收集器的交互特别糟糕,因为它需要将指针保持在对象的中间(在基础的开头)。 )
在设计C#时,我认为他们看着Java,看到了完全多重继承的确并没有错失太多,因此也选择保持简单。
C ++如何解决从多个基类继承的相同方法签名的歧义?
事实并非如此。有一种语法可以从特定的基础显式地调用基类方法,但是无法覆盖仅一个虚拟方法,并且如果您不覆盖子类中的方法,则在不指定基础的情况下就无法调用它类。
为什么同一个设计没有合并到C#中?
没有什么可以合并的。
由于Giorgio在评论中提到了接口扩展方法,因此我将解释什么是mixin以及如何以各种语言实现它们。
Java和C#中的接口仅限于声明方法。但是必须在继承该接口的每个类中实现这些方法。但是,存在大量的接口,在其中提供一些方法的默认实现会很有用。常见示例是可比较的(使用伪语言):
mixin IComparable {
public bool operator<(IComparable r) = 0;
public bool operator>(IComparable r) { return r < this; }
public bool operator<=(IComparable r) { return !(r < this); }
public bool operator>=(IComparable r) { return !(r > this); }
public bool operator==(IComparable r) { return !(r < this) && !(r > this); }
public bool operator!=(IComparable r) { return r < this || r > this; }
};
与完整类的区别在于,它不能包含任何数据成员。有几种实现方法。显然,多重继承是其中之一。但是多重继承的实现相当复杂。但这并不是真正需要的。取而代之的是,许多语言通过在一个由类实现的接口和方法实现的存储库中拆分混合来实现此目的,这些接口要么注入到类本身中,要么生成一个中间基类,然后将它们放置在该类中。这是在Ruby和D中实现的,将在Java 8中实现,并且可以使用奇怪的重复模板模式在C ++中手动实现。上面的CRTP格式如下:
template <typename Derived>
class IComparable {
const Derived &_d() const { return static_cast<const Derived &>(*this); }
public:
bool operator>(const IComparable &r) const { r._d() < _d(); }
bool operator<=(const IComparable &r) const { !(r._d() < _d(); }
...
};
的使用方式如下:
class Concrete : public IComparable<Concrete> { ... };
这不需要像常规基类那样将任何东西声明为虚拟的,因此,如果在模板中使用该接口,则会打开有用的优化选项。请注意,在C ++中,它可能仍将作为第二父级继承,但是在不允许多重继承的语言中,它将插入到单个继承链中,因此更像
template <typename Derived, typename Base>
class IComparable : public Base { ... };
class Concrete : public IComparable<Concrete, Base> { ... };
编译器实现可能会也可能不会避免虚拟分派。
在C#中选择了其他实现。在C#中,实现是完全独立的类的静态方法,如果给定名称的方法不存在,但定义了“扩展方法”,则编译器会适当地解释方法调用语法。这样做的优点是可以将扩展方法添加到已编译的类中,而缺点是不能覆盖此类方法(例如提供优化版本)。
答案是在命名空间冲突的情况下,它在C ++中无法正常工作。看到这个。为了避免名称空间冲突,您必须使用指针进行各种旋转。我在Visual Studio团队的MS部门工作,至少部分原因是他们开发了委派的原因是完全避免名称空间冲突。之前我曾说过,他们也认为接口是多重继承解决方案的一部分,但我误会了。接口实际上是很棒的,可以在C ++,FWIW中使用。
委托专门解决名称空间冲突:您可以委托5个类,所有5个类都将其方法作为第一类成员导出到您的作用域中。从外部看,这是多重继承。