在派生类中隐式隐藏同名的基类方法 - 为什么? [英] implicit hiding of same-named methods of base class in derived classes - why?

查看:111
本文介绍了在派生类中隐式隐藏同名的基类方法 - 为什么?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

这段代码不会编译(两个编译器尝试过,gcc和VC ++,这两个版本都是最新版本,但我完全不记得它们):

This code won''t compile (two compilers tried, gcc and VC++, both of recent versions, but I don''t remember them exactly):

展开 < span class =codeDivider> | 选择 | Wrap | Line数字

推荐答案

让我们分段:

Let''s take these in sections:


这是因为C ++编译器假定您要完全重新定义基类''方法,如果您使用具有相同名称的方法,即使它具有不同的签名。
This happens because the C++ compiler assumes you want to redefine the base class''es methods completely, if you use a method with the same name, even if it has a different signature.



不正确。


C ++有函数重载但你不能在基类和派生类之间重载。在类层次结构中,与基类方法同名的派生类方法称为DOM DOMINATE基类方法。


这意味着调用该方法的派生对象将调用派生方法,并且如果派生对象试图通过具有基本参数来调用基本方法,那么它就不会因为统治而编译。


在这最后一种情况下你有你明确调用基本方法:


deivedObject.base :: themethod(等等)


下一页:

is not true.

C++ has function overloading but you cannot overload between a base class and a derived class. In a class hierarchy, a derived class method with the same name as a base class method is said ro DOMINATE the base class method.

That means a derived object calling the method will call the derived method and further, if the derived object tries to call the base method by having the base arguments, it won''t compile becuse of the domination.

In this last case you have you make an explicit call to the base method:

deivedObject.base::themethod(etc..)

Next:


但是,如果在派生类中没有完全相似的话,为什么要隐藏基类''方法呢?
But otherwise, why hide a base class''es method away, if there''s nothing exactly similar in a derived class?



假设你有门类。您可以使用Open方法打开门。关于门的大小,门的图像等还有其他方法。


现在你需要一个只用魔法打开的门。有各种各样的解决方案,但一种解决方案是从门派生出MagicDoor并重新定义Open方法以获取具有魔法咒语的char *。然后你使用魔术门对象。所有其他的Door方法都将被继承。

Suppose you have Door class. You open the door by using the Open method. There are other methods about the size of the door, the grpahical image of the door, etc.

Now you have a requirement for a Door that opens only with a magic spell. There are various solurtions, but one solution is to derived MagicDoor from Door and redefine the Open method to take a char* that has the magic spell. Then you use Magic Door objects. All of the other Door methods will be inherited.


OOP表示派生类的对象是一种与基类相同的对象class''es对象,只有附加和/或更改的功能 - 但我从来没有听说过任何人说publicky派生类的对象实际上可能比基类的对象具有更少的功能。总是假设公开派生的类扩展了基本classe的功能,而不是限制它。
OOP says that objects of a derived class are a kind of objects of the same class as the base class''es objects, only with additional and/or changed functionality - but I never heard anybody say that objects of publicky derived classes may actually have less functionality than the objects of the base class. It is always assumed that publicly derived classes expand the functionality of the base classe, and don''t restrict it.



这不是真的。


派生类可能具有比基类更多或更少的功能。如果派生类具有比基类更多的功能,并且您拥有的只是指向派生对象的基类指针,则可以使用访问者设计模式作为派生对象指针访问派生对象,以便您可以调用这些附加派生类方法。


实际上,我会说正常的情况是使用比基类具有更多功能的派生对象来操作 - 并且通过使用基类指针来多态地执行此操作这些对象和没有类型转换或RTTI或其他愚蠢。


那么接口与实现的问题。接口是基类中的公共方法。实现是这些方法的实现方式。通常,您会看到公共虚拟功能。这是一个常见的设计错误。虚函数应始终是私有的,以便将接口与实现分开。通常,基类具有由私有派生类虚方法覆盖的私有虚函数。实际上,您从基类调用派生方法。这被称为好莱坞原则。 (不要打电话给我们,我们会打电话给你)。一旦开始这样做,您的基类与派生类几乎没有相似之处。

This is just not true.

A derived class may have more or less functionality than the base class. If the derived class has more functionality than the base class and all you have is a base class pointer to the derived object, you use the Visitor design pattern to gain access to the derived object as a derived object pointer so you can call these additional derived class methods.

In fact, I would say the normal case is to operate with derived objects that have more funcitonality than the base class - and to do this polymorphically by using a base class pointer to these objects AND NO type-casting or RTTI or other silliness.

Then there''s the question of interface vs implementation. The interface is the public methods in the base class. The implementation is how those methods are implemented. Normally, you see public virtual functions. This is a common design error. Virtual functions should always be private so as to separate the interface from the implementation. Often the base class has private virtual functions that are overriden by private derived class virtual methods. In effect you call derived methods from the base class. This is called the "Hollywood Principle" (don''t call us we''ll call you). Once you start doing this, your base class bears little resemblance to your derived class.


不止于此:应始终可以用派生类的对象替换基类的对象。这种语言功能有效地防止了这个
More than that: it should be always possible to substitute an object of a base class with an object of a derived class. This language feature effectively prevents this



你永远不能将派生类的对象替换为基类的对象。当你这样做时,对象的派生部分被切掉,你开始使用截肢者。不幸的是,VTBL仍处于剩下的部分,当你调用其中一个需要从对象中删除数据的方法时,你会崩溃。


这是真的,是吗您始终可以将派生类POINTER或REFERENCE替换为基类指针或引用。它必须是指针或引用,否则虚函数机制将无法工作。基本原则是派生对象可以构成基础对象,但这只能通过地址或引用来完成。

You can NEVER substitiute an obect of a derived class for an object of the base class. When you do, the derived portion of the object is sliced off and you begin working with an amputee. Unfortunately, the VTBL is still in the remaining portion and when you call one of those methods that need data that has been chopped off the object, you crash.

What is true, is that you can always substitute a derived class POINTER or a REFERENCE for a base class pointer or reference. It must be a pointer or reference or the virtual function mechanism won''t work. The underlying principle is the derived object can pose as a base object but this is done by address or reference only.



假设你有门类。您可以使用Open方法打开门。关于门的大小,门的图像等还有其他方法。


现在你需要一个只用魔法打开的门。有各种各样的解决方案,但一种解决方案是从门派生出MagicDoor并重新定义Open方法以获取具有魔法咒语的char *。然后你使用魔术门对象。所有其他Door方法都将被继承。
Suppose you have Door class. You open the door by using the Open method. There are other methods about the size of the door, the grpahical image of the door, etc.

Now you have a requirement for a Door that opens only with a magic spell. There are various solurtions, but one solution is to derived MagicDoor from Door and redefine the Open method to take a char* that has the magic spell. Then you use Magic Door objects. All of the other Door methods will be inherited.



对。但更多时候我想派生一个WoodenDoor或IronDoor,除了继承open()方法之外,还要添加一个open(int sqeakLevel)。而不是自动发生这种情况,我必须明确说明这一点。


另一方面,如果我同时编写了Door和MagicDoor类,还有其他人编写了一个Robot类,有一个方法openDoor(Door * pDoor),我传给它一个MagicDoor *,它会打开MagicDoor而没有一个咒语 - 编译器不会抱怨。我缺少什么?

Right. But more often I want to derive a WoodenDoor or an IronDoor, and besides inheriting the open() method, also add an open(int sqeakLevel). Instead of this happening automatically, I have to explicitly state this.

On the other hand, if I have written both the Door and the MagicDoor classes, and somebody else has written a Robot class, which has a method openDoor(Door* pDoor), and I pass it a MagicDoor*, it will open the MagicDoor without a spell - the compiler won''t complain. What am I missing?


派生类可能具有比基类更多或更少的功能。
A derived class may have more or less functionality than the base class.



我同意。尽管如此,创建具有较少功能的派生类并不是一件好事。如果这是可取的,我现在就不会想到任何情况。你使用的门示例一方面是弱的(参见上面的愚蠢机器人,它忽略了你不想在没有法术的情况下打开MagicDoor的事实),另一方面你通常想要复杂/增强功能一扇门(见上面吱吱作响的门),而不是削弱基层的功能。


我根本不是说你不需要的情况削弱基类。我认为这是一个不太常见的情况,相比之下你需要基类中的所有内容然后一些。

I agree. Still, it''s not nice OOP to create derived classes with less functionality. I can think of no case right now when this would be desirable. The Door example you used is on one hand weak (see the stupid Robot above, which ignores the fact that you don''t want the MagicDoor opened without a spell), on the other hand you usually want to complicate/enhance the functionality of a Door (see the Doors which squeak above), rather than cripple the base class''es functionality.

I don''t mean at all that the case is impossible that you need to cripple the base class. I just think that it is a much less common case compared to the case where you need all that''s there in the base class and then some.


您永远不能将派生类的对象替换为基类的对象。
You can NEVER substitiute an obect of a derived class for an object of the base class.



同意。因为我习惯于垃圾收集语言,你从不操纵对象或指针,但总是使用引用,我使用对象,指向对象的指针,对象的引用可互换 - 这当然是C ++的完全混乱程序员。但是,我的意思是指针。


总结:

Agree. Since I''m used to garbage-collected languages, where you never manipulate objects or pointers to them, but always use references, I use object, pointer to object, reference of object interchangeably - which is of course a complete messup for a C++ programmer. However, I meant pointers.

To summarize:


C ++有函数重载但你不能在基类之间重载派生类。
C++ has function overloading but you cannot overload between a base class and a derived class.



这正是我的问题:为什么?语言设计师为什么决定这个? IMO,你经常需要/想要在基类和派生类之间重载,而不是通过简单地添加一个新的,类似命名的方法来重新定义/隐藏所有基类''方法。


然而,语言设计师可能比我更聪明,所以他们一定有理由。有人可以告诉我原因吗?

That''s exactly my problem: why? Why did the language designers decide this? IMO, you often need/want to overload between a base class and a derived class, instead of re-defining/hiding away all the base class''es methods by simply adding a new, similarly-named method.

However, the language designers were probably much smarter than I am, so they must have had a reason. Can anybody tell me the reason?



对。但更多时候我想派生一个WoodenDoor或IronDoor,除了继承open()方法之外,还要添加一个open(int sqeakLevel)。而不是自动发生这种情况,我必须明确说明这一点。


另一方面,如果我同时编写了Door和MagicDoor类,还有其他人编写了一个Robot类,有一个方法openDoor(Door * pDoor),我传给它一个MagicDoor *,它会打开MagicDoor而没有一个咒语 - 编译器不会抱怨。我错过了什么?
Right. But more often I want to derive a WoodenDoor or an IronDoor, and besides inheriting the open() method, also add an open(int sqeakLevel). Instead of this happening automatically, I have to explicitly state this.

On the other hand, if I have written both the Door and the MagicDoor classes, and somebody else has written a Robot class, which has a method openDoor(Door* pDoor), and I pass it a MagicDoor*, it will open the MagicDoor without a spell - the compiler won''t complain. What am I missing?



这是一个无法将实现与接口分开的问题。你通过使用公共虚拟功能进入这个泡菜。虚函数定义了实现,我是如何做到的。接口是基类中的公共成员函数集。这些成员函数都不应该是虚拟的。


您正在解决所有门打开的问题。只是有些门打开的方式与其他门不同。因此,在您的基类中,您只有一个Open()方法:

This is a problem with failing to separate the implementation from the interface. You get into this pickle by using public virtual functions. The virtual functions define the implementation, the "how I did it". The interface is the set of public member functions in the base class. None of these member functions should ever be virtual.

You are addressing that "all doors open". It''s just that some doors open differently from others. Therefore, in your base class, you just have an Open() method:

展开 | 选择 | Wrap | 行号


这篇关于在派生类中隐式隐藏同名的基类方法 - 为什么?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆