This is not exactly the case. If you call a dynamically-bound method inside a constructor, the overridden definition for that method is used. However, the effect can be rather unexpected and can conceal some difficult-to-find bugs.
Conceptually, the constructor’s job is to bring the object into existence (which is hardly an ordinary feat). Inside any constructor, the entire object might be only partially formed—you can know only that the base-class objects have been initialized, but you cannot know which classes are inherited from you. A dynamically bound method call, however, reaches “outward” into the inheritance hierarchy. It calls a method in a derived class. If you do this inside a constructor, you call a method that might manipulate members that haven’t been initialized yet—a sure recipe for disaster.
In Glyph, the draw( ) method is abstract, so it is designed to be overridden. Indeed, you are forced to override it in RoundGlyph. But the Glyph constructor calls this method, and the call ends up in RoundGlyph.draw( ), which would seem to be the intent. But if you look at the output, you can see that when Glyph’s constructor calls draw( ), the value of radius isn’t even the default initial value 1. It’s 0. This would probably result in either a dot or nothing at all being drawn on the screen, and you’d be left staring, trying to figure out why the program won’t work.
The order of initialization described in the earlier section isn’t quite complete, and that’s the key to solving the mystery. The actual process of initialization is:
1. The storage allocated for the object is initialized to binary zero before anything else happens.
2. The base-class constructors are called as described previously. At this point, the overridden draw( ) method is called (yes, before the RoundGlyph constructor is called), which discovers a radius value of zero, due to Step 1.
3. Member initializers are called in the order of declaration.
4. The body of the derived-class constructor is called.
There’s an upside to this, which is that everything is at least initialized to zero (or whatever zero means for that particular data type) and not just left as garbage. This includes object references that are embedded inside a class via composition, which become null. So if you forget to initialize that reference, you’ll get an exception at run time. Everything else gets zero, which is usually a telltale value when looking at output.
On the other hand, you should be pretty horrified at the outcome of this program. You’ve done a perfectly logical thing, and yet the behavior is mysteriously wrong, with no complaints from the compiler. (C++ produces more rational behavior in this situation.) Bugs like this could easily be buried and take a long time to discover.
As a result, a good guideline for constructors is, “Do as little as possible to set the object into a good state, and if you can possibly avoid it, don’t call any methods.” The only safe methods to call inside a constructor are those that are final in the base class. (This also applies to private methods, which are automatically final.) These cannot be overridden and thus cannot produce this kind of surprise.
When studying inheritance, it would seem that the cleanest way to create an inheritance hierarchy is to take the “pure” approach. That is, only methods that have been established in the base class or interface are to be overridden in the derived class, as seen in this diagram:
Fig. 3 Interface
This can be called a pure “is-a” relationship because the interface of a class establishes what it is. Inheritance guarantees that any derived class will have the interface of the base class and nothing less. If you follow this diagram, derived classes will also have no more than the base-class interface.
This can be thought of as pure substitution, because derived class objects can be perfectly substituted for the base class, and you never need to know any extra information about the subclasses when you’re using them:
- 上一篇:电子商务英文文献和中文翻译
- 下一篇:搅拌釜内混合液体的分离涡模拟英文文献和中文翻译
-
-
-
-
-
-
-
现代简约美式风格在室内家装中的运用
高警觉工作人群的元情绪...
NFC协议物理层的软件实现+文献综述
上市公司股权结构对经营绩效的影响研究
浅析中国古代宗法制度
巴金《激流三部曲》高觉新的悲剧命运
C++最短路径算法研究和程序设计
g-C3N4光催化剂的制备和光催化性能研究
江苏省某高中学生体质现状的调查研究
中国传统元素在游戏角色...