To realize polymorphism in Object-Oriented Programming, virtual functions are a topic. The so-called virtual function means that the derived class and the base class have the same function name, but their functions are implemented differently. In C ++, the operator that defines virtual functions adds the keyword virtual before the declaration of class member functions. However, in practical applications, even if you do not need virtual functions, you can also use the member functions with the same name to achieve polymorphism.
In C ++ primer plus, Stephen assumes that a virtual function should be used. If you want to use the same base class pointer to indicate objects of the base class and the derived class, the member functions used to implement polymorphism are not set to virtual functions. So isn't it that the same pointer can be used to call an object of the same name with the keyword virtual? Recently I have been entangled in this issue.
In the fourth question in chapter 13 of the book, Mr. Stephen gave the definition of a base class and a derived class respectively:
Class port <br/>{< br/> PRIVATE: <br/> char * Brand; <br/> char style [20]; <br/> int bottles; <br/> Public: <br/> port (const char * BR = "NONE", const char * ST = "NONE", int B = 0 ); <br/> port (const Port & P); <br/> virtual ~ Port () {Delete [] brand ;}< br/> Port & operator = (const Port & P); <br/> Port & operator ++ = (int B ); <br/> Port & operator-= (int B); <br/> int bottlecount () const {return bottles ;}< br/> virtual void show () const; <br/> friend ostream & operator <(ostream & OS, const Port & P); <br/>}; <br/> class vintageport: public port <br/>{< br/> PRIVATE: <br/> char * nickname; <br/> int year; <br/> public: <br/> vintageport (); <br/> vintag Eport (const char * Br, const char * St, int B, const char * NN, int y); <br/> vintageport (const vintageport & vp ); <br/> ~ Vintageport () {Delete [] nickname ;}< br/> vintageport & operator = (const vintageport & vp); <br/> void show () const; <br/> friend ostream & operator <(ostream & OS, const vintageport & vp); <br/> };
There is a small question in the question: why are there no virtual functions set for the two functions in the declaration that reload the "=? At first glance, I had a question. In the past, I only studied the reasons for using virtual functions. Here I can explain the reasons for not having to use virtual functions. Then I thought in turn, what are the consequences of checking their virtual function features after adding the virtual keyword to the two overloaded functions with equal signs?
Virtual Port & operator = (const Port & P); <br/> virtual vintageport & operator = (const vintageport & vp );
The following is a test function that defines two derived class objects and a base class pointer. The base class Pointer Points to the object of the second derived class. Use the pointer-Based Domain resolution operator "->" to explicitly call the "=" overload function to direct the first derived class object to the second derived class Object pointed to the base class pointer:
Int main () <br/>{< br/> vintageport p1 = vintageport ("Riesling", "whitewine", 70, "leisiling", 1970 ); <br/> vintageport P2 = vintageport ("Cabernet", "redwine", 30, "jiebaina", 1990); <br/> port * PP2 = & P2; <br/> PP2-> operator = (P1); // explicitly call the "=" overload function <br/> cout <P2 <Endl; <br/> return 0; <br/>}
This is the method definition used in the program. I wrote it myself:
Port: Port (const char * Br, const char * St, int B) <br/>{< br/> brand = new char [strlen (BR) + 1]; <br/> strcpy (brand, Br); <br/> strcpy (style, St); <br/> bottles = B; <br/>}< br/> port: Port (const Port & P) <br/>{< br/> brand = new char [strlen (P. brand) + 1]; <br/> strcpy (brand, P. brand); <br/> strcpy (style, P. style); <br/> bottles = P. bottles; <br/>}< br/> Port & Port: Operator = (const Port & P) <br/>{< br/> If (& P = This) <br/> return * This; <br/> Delete [] brand; <br/> brand = new char [strlen (P. brand) + 1]; <br/> strcpy (brand, P. brand); <br/> strcpy (style, P. style); <br/> bottles = P. bottles; <br/> return * This; <br/>}< br/> ostream & operator <(ostream & OS, const Port & P) <br/> {<br/> OS <p. brand <',' <p. style <',' <p. bottles; <br/> return OS; <br/>}< br/> vintageport: vintageport () <br/>{< br/> nickname = new char [5]; <br/> strcpy (nickname, "NONE"); <br/> year = 2000; <br/>}< br/> vintageport: vintageport (const char * Br, const char * St, int B, const char * NN, int y) <br/>: port (BR, St, B) <br/>{< br/> nickname = new char [strlen (NN) + 1]; <br/> strcpy (nickname, nn); <br/> year = y; <br/>}< br/> vintageport & vintageport: Operator = (const vintageport & vp) <br/>{< br/> If (& Vp = This) <br/> return * This; <br/> Delete [] nickname; <br/> Port:: Operator = (VP); <br/> nickname = new char [strlen (VP. nickname) + 1]; <br/> strcpy (nickname, VP. nickname); <br/> year = VP. year; <br/> return * This; <br/>}< br/> ostream & operator <(ostream & OS, const vintageport & vp) <br/> {<br/> OS <(const Port &) VP <',' <vp. nickname <',' <vp. year; <br/> return OS; <br/>}
The running result shows a nondescribable "Riesling, whitewine, 70, jiebaina, 1990 ". Originally, it only copies the base class part of the member, and the added part of the derived class is not dynamic. Obviously, the pointer of this base class only points to the same name method of the base class. Why shouldn't this happen after virtual functions are set? I was puzzled, so I searched for the answer in csdn. Finally, a post attracted my attention:
Http://topic.csdn.net/u/20100318/20/41c77e2a-cc32-4d56-b78a-a32c79f4c288.html
It discusses the relationship between operator overload functions and virtual functions. The reply on the fifth floor awakened the dreamer. I was eager to go through the book to find the description of the virtual function. There was such a sentence in the book.
If you redefine the inherited method, make sure it is exactly the same as the original prototype.
This sentence may be a bit ambiguous and did not attract my attention at the time. Some of the replies in the post are clear:
According to the definition of the virtual function, the names, parameter types, and numbers of the base class and derived class functions must be the same. However, if the parameters of the two functions are different, the virtual function loses its meaning, become a common overload function.
The problem seems to have been solved. The error occurs in the understanding of the word "redefinition". The function name is the same, but the prototype must be the same. Then, you have to go to the working principle of the virtual function to explain why "->" cannot be used here to get satisfactory results. Virtual functions are implemented based on the virtual function table vtbl, which describes the vtbl Operating Mechanism in the book:
The virtual function table stores the virtual function addresses declared for class objects. For example, a base class object contains a pointer pointing to the address table of all functions in the base class. The derived class object also contains a pointer to an independent address table. If the derived class provides the definition of a virtual function, the function table will save the address of the new function. If the derived classNo new virtual function defined
, The vtbl willSave Original Version
.
The prototype of the "=" overload function in the derived class is different from that of the base class. Therefore, according to the previous expression, it can be called "No redefinition of virtual functions ". Vtbl naturally saves the address of the original version, that is, the entry address of the base class's equivalent number overload function. Therefore, it is not surprising that the result of the "->" operator appears.
Here are some additional questions. As mentioned in the reply, functions with the same name but different prototype in the base class and the derived class will become common overload functions. I personally think this statement is incorrect. The book mentions that if the two virtual functions have the same name in the base class and the derived class, but the prototype is not exactly the same, the base class version will be automatically hidden when the derived class object is called. However, I have not explained common functions with the same name but different prototype functions. According to my experiment, in this case, functions with the same name of the base class will still be hidden: (it is the result of intelligencesense in vs2008 without the virtual keyword declaration .)
IDE only detects the operator overload function of a derived class, that is, the base class version is blocked. In my opinion, this is necessary because the derived type can be forcibly converted up, and the "=" Number of the base class and the derived class can accept the object of the derived class, which may cause ambiguity.
I am confused after so many times. Of course, what I am talking about now only represents a beginner's understanding of the C ++ world. I am not sure that this is absolutely correct. I hope you can correct me!