How to Implement polymorphism in C ++

Source: Internet
Author: User

In fact, there is nothing to say. I just did a test to find out why there are some inexplicable rules.
I have never understood this before when I learned C ++. I hope it will be helpful to some people ~~
The following source code is passed in VC ++ 6.0.
The tab only occupies 1 cell. Let's take a look at it =. = Or copy to the editor =. =

 

 

// File name: polymorphism_test.cpp
// Author: keakon
// Create Date: 2006/5/11
// Last edited Date: 2006/5/26
// Three tests demonstrate how to implement polymorphism.

# Include <iostream>
# Include <iterator>
# Include <ostream>
# Include <string>

Using STD: cerr;
Using STD: cout;
Using STD: string;

// Real coverage
Class A1
{
Public:
A1 (string const & name): m_name (name) {cout <getname () <"A1: A1 ()/n ";}
~ A1 () {cout <getname () <"A1 ::~ A1 ()/n ";}
Void print () const {cout <getname () <"A1: Print ()/n ";}
Protected:
String const & getname () const {return m_name ;}
PRIVATE:
String m_name;
};

Class A2: Public A1
{
Public:
A2 (string const & name): A1 (name) {cout <getname () <"A2: A2 ()/n ";}
~ A2 () {cout <getname () <"A2 ::~ A2 ()/n ";}
Void print () const {cout <getname () <"A2: Print ()/n ";}
};

// Virtual Overwrite
Class B1
{
Public:
B1 (string const & name): m_name (name) {cout <getname () <"B1: B1 ()/n ";}
Virtual ~ B1 () {cout <getname () <"B1 ::~ B1 ()/n ";}
Virtual void print () const {cout <getname () <"B1: Print ()/n ";}
Protected:
String const & getname () const {return m_name ;}
PRIVATE:
String m_name;
};

Class B2: Public B1
{
Public:
B2 (string const & name): B1 (name) {cout <getname () <"B2: B2 ()/n ";}
Virtual ~ B2 () {cout <getname () <"B2 ::~ B2 ()/n ";}
Virtual void print () const {cout <getname () <"B2: Print ()/n ";}
};

// Overwrite virtual data and use real destructor (this is an error)
Class C1
{
Public:
C1 (string const & name): m_name (name) {cout <getname () <"C1: C1 ()/n ";}
~ C1 () {cout <getname () <"C1 ::~ C1 ()/n ";}
Virtual void print () const {cout <getname () <"C1: Print ()/n ";}
Protected:
String const & getname () const {return m_name ;}
PRIVATE:
String m_name;
};

Class C2: Public C1
{
Public:
C2 (string const & name): C1 (name) {cout <getname () <"C2: C2 ()/n ";}
~ C2 () {cout <getname () <"C2 ::~ C2 ()/n ";}
Virtual void print () const {cout <getname () <"C2: Print ()/n ";}
};

// Separate the output of each part
Void printline (unsigned int Height = 1, unsigned int length = 20,
Char CH = '-', STD: ostream & out = cout)
{
Const string line (length, CH );

For (; height! = 0; -- height)
{
// Output a row of ch on the out
STD: Copy (line. Begin (), line. End (), STD: ostream_iterator <char> (out ));
Out <'/N ';
}
}

// Test
Int main ()
{
Try
{
// Real coverage
Cout <"Real override 1:/N ";
{
Printline ();
A1 A1 ("A1 .");
Printline ();
A2 A2 ("A2 .");
Printline (2 );

A1.print ();
Printline ();
A2.print (); // call a2.a2: Print ()
Printline ();
Static_cast <A1> (A2). Print ();
// Call A1: A1 (A1 &) or A1: A1 (A1 const &) to generate a temporary A1 variable
// Then this temporary variable calls A1: Print ()
// After the statement is out of scope (when the statement ends), A1 ::~ will be called ::~ A1 ()
// For more information, see note 4.
Printline ();
A2.a1: Print (); // unlike the previous sentence, the Destructor is not called here.

Printline (2 );
} // Beyond the scope, call the destructor. curly brackets are also used in the same format.

Printline (3 );

// An error may occur when the pointer is used to implement real coverage.
Cout <"Real override 2:/N ";
{
Printline ();
A1 * pa1 = new A1 ("pa1-> ");
Printline ();
A1 * pa2 = new A2 ("pa2->"); // the pointer of the base class.
Printline ();
A2 * pa3 = new A2 ("pa3-> ");
Printline ();
A2 A4 ("A4 .");
A1 * pa4 = & A4; // the pointer of the base class.
A1 & ra2 = * pa2; // note that the base class is referenced.
Printline (2 );

Pa1-> Print (); // pointer not checked, because the new will throw an exception when an error occurs
Printline ();
Pa2-> Print (); // call pa2-> A1: Print ()
Printline ();
Pa3-> Print (); // call pa3-> A2: Print ()
Printline ();
Pa4-> Print (); // call a4.a1: Print (), that is, pa4-> A1: Print ()
Printline ();
Ra2.print ();
Printline (2); // call pa2-> A1: Print ()

Delete pa1;
Printline ();
Delete pa2; // error, (* pa2). A2 ::~ A2 () won't be called
Printline ();
Delete pa3;
Printline ();
Pa1 = NULL;
Pa2 = NULL;
Pa3 = NULL;
Pa4 = NULL; // pa4 is not new and does not need to be deleted.
}

Printline (3 );

// Some of the same tests will not be overwritten again below

// Virtual Overwrite
Cout <"virtual override 1:/N ";
{
Printline ();
B1 B1 ("B1 .");
Printline ();
B2 B2 ("B2 .");
Printline ();

B1.print ();
Printline ();
B2.print (); // call b2.b2: Print (), same as the real function.
Printline ();
}

Printline (3 );

Cout <"virtual override 2:/N ";
{
Printline ();
B1 * PB1 = new B1 ("PB1-> ");
Printline ();
B1 * PBS = new B2 ("PBS->"); // note that the pointer to the base class
Printline ();
B1 & Rb2 = * PBS; // note that the base class is referenced.
Printline ();

PB1-> Print ();
Printline ();
Master-> Print (); // call the master-> B2: Print ()
Printline ();
Rb2.print (); // call the following link ()
Printline ();

Delete PB1;
Printline ();
Delete PBS;
PB1 = NULL;
PBS = NULL;
}

Printline (3 );

// Overwrite virtual data and use real destructor (this is an error)
Cout <"virtual override 1, using real destruction:/N ";
{
Printline ();
C1 C1 ("C1 .");
Printline ();
C2 C2 ("C2 .");
Printline (2 );

C1.print ();
Printline ();
C2.print ();
Printline (2 );
}

Printline (3 );

Cout <"virtual override 2, using real destruction:/N ";
{
Printline ();
C1 * pC1 = new C1 ("pC1-> ");
Printline ();
C1 * PC2 = new C2 ("PC2->"); // note that the base class pointer
Printline (2 );

PC1-> Print ();
Printline ();
PC2-> Print (); // PC2-> C2 ::~ C2 () won't be called
Printline (2 );

Delete pC1;
Printline ();
Delete PC2;
Cout <STD: Endl;
PC1 = NULL;
PC2 = NULL;
}

Return 0;
}

Catch (STD: bad_alloc &)
// If the memory is not enough, new throws STD: bad_alloc
// It seems that this exception will never be thrown under VC ++, but it will not be an error. In the compiler such as G ++, this exception will be thrown.
{
Cerr <"/Nno enough memory! /N ";
Return 1;
}

Catch (...)
{
Cerr <"/n finds unknown exceptions. Maybe you have problems with your character. ";
Return 2;
}
}

/*
Note: in fact, the format does not need to be written like this, and many do not need to be tested. However, to facilitate the comparison, I still write it like this.

Conclusion:

1. When you call a member function directly through an object, the member function of the class of the object is always used by default (unless you use: to display the specified class name ).

2. When calling a member function by pointing to an object pointer or referencing it:
If the function is a real function, call the pointer or referenced class member function;
If this function is a virtual function, call this pointer or reference a member function of the class of the object to which it points.

3. The basic destructor must be a virtual function in this case (in this case, the destructor of the derived class will also be a virtual function ):
Use new to create a derived class object, and use the pointer for the delete operation as the base class pointer.
If it is a real destructor, the members of the derived class will not be destructed.

4. If no replication constructor is defined, do not convert the forced type of a derived class object to the base class object.
If the copy constructor is not explicitly defined, the compiler generates a default copy constructor.
However, this default copy constructor will not do anything else you want to do, such:
If you want to maintain the counter of a class object in the constructor, this function will not increase the counter;
If you want to create a new object in the constructor, this function will not create the new object.
The default copy constructor performs a shortest copy, and the Members used are all original objects.
Therefore, in the analysis of this temporary object, the delete object is the new object of the original object;
The original object will delete this object again during the analysis; this is an undefined behavior and may cause program crash.
In addition, even in the destructor, after deleting the object, it is invalid to assign a null value to the pointer to this object;
Because the pointer of the temporary object is changed, the pointer of the original object still points to the deleted object.

I actually wrote another test code to prove the conclusion of the 4th point.
But the test code was too messy during the last test and I will not give it.
If you are interested, you can add static object counters, object pointers, and copy constructor for the A1 and A2 classes, and then study them on your own.
When I tested on VC ++ 6.0 SP6, the running status in debug and release modes was actually different (the former crashes and the latter looks normal ).
However, I haven't had much time to study it and asked many people but no one gave a correct answer.
Finally, I had to track the disassembly code myself. Thanks to the debugger of VC ++.
*/

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.