scene
-
In developing C++ programs, polymorphic references and pointers are often used. What's the difference between them?
-
When will polymorphic references and pointers call virtual function tables and when not?
-
Polymorphic references and pointers are methods of subclasses or superclasses of calls?
Explain
Reference variable
-
Reference variable is a compound type added by C++ relative to C. It is an alias of defined variable. Note that it is a defined variable and must refer to a defined variable. Therefore, the reference variable must be initialized when declared.
-
Reference types use & to declare references, similar to pointer * to declare pointers. For ex amp le, the following ii is a reference variable.
int i; int& ii = i; -
As an alias for a defined variable, any operation on a defined variable can be used in a reference variable, such as taking an address, assigning a value, etc. Modifying the equivalent of a reference variable means modifying the value of a defined variable. Generally, when a variable is referred to as a function parameter, the value of the function parameter is modified, that is, the value of the defined variable. For example, int&ii.
polymorphic
-
Polymorphism can literally explain the various forms of behavior. Generally speaking, it refers to the same method. The behavior of subclasses and base classes is different, that is, inheritance.
-
References or pointers can take advantage of polymorphism, and their behavior in calling methods depends on the type of variables that call them or the type of actual objects.
-
References and pointers call virtual function tables only when methods are declared as virtual functions.
-
When a method is declared as a virtual function, the reference and pointer call the method of the actual object, such as the actual object is a subclass, and the invocation of the reference variable is a base class, then the virtual function of the subclass is invoked.
-
Instead of the method of virtual function, according to the method invoked, the method of variable type is called, even if the subclass overloads the method of base class. For example, if the calling variable is a pointer to the base class, and the object to which it points is a subclass object, then the method of the base class is still invoked.
-
When we write a class, we often need to declare the destructor as a virtual method. The purpose of this is to call the destructor of the parent class automatically when the subclass destructs. Some compilers will automatically add virtual to the destructor of each class, and will automatically call the destructor of the parent class when destructing. For example, LLVM 5.1 here.
The difference between reference and pointer
-
Reference is not an address, and pointers often represent an address.
-
A reference must be an alias for a defined object, not NULL.
-
Class references are commonly used. As symbols for calling attribute methods, pointers need to use - >.
-
Reference types and pointer types can be converted using four types of conversion operators in C++.
Example
Brass.h
// // Brass.h // TestC++11 // // Created by sai on 8/23/19. // Copyright (c) 2019 sai. All rights reserved. // #ifndef __TestC__11__Brass__ #define __TestC__11__Brass__ #include <iostream> class Brass { public: void TestAdd(); void TestVirtualAdd(); virtual ~Brass(); }; #endif /* defined(__TestC__11__Brass__) */
Brass.cpp
// // Brass.cpp // TestC++11 // // Created by sai on 8/23/19. // Copyright (c) 2019 sai. All rights reserved. // #include "Brass.h" void Brass::TestAdd() { std::cout << "Brass::TestAdd" << std::endl; } Brass::~Brass() { std::cout << "Brass::~Brass: " << (int64_t)this << std::endl; } void Brass::TestVirtualAdd() { std::cout << "Brass::TestVirtualAdd" << std::endl; }
BrassPlus.h
// // BrassPlus.h // TestC++11 // // Created by sai on 8/23/19. // Copyright (c) 2019 sai. All rights reserved. // #ifndef __TestC__11__BrassPlus__ #define __TestC__11__BrassPlus__ #include <iostream> #include "Brass.h" class BrassPlus: public Brass { public: void TestAdd(); void TestVirtualAdd(); ~BrassPlus(); }; #endif /* defined(__TestC__11__BrassPlus__) */
BrassPlus.cpp
// // BrassPlus.cpp // TestC++11 // // Created by sai on 8/23/19. // Copyright (c) 2019 sai. All rights reserved. // #include "BrassPlus.h" void BrassPlus::TestAdd() { std::cout << "BrassPlus::TestAdd" << std::endl; } void BrassPlus::TestVirtualAdd() { std::cout << "BrassPlus::TestVirtualAdd" << std::endl; } BrassPlus::~BrassPlus() { std::cout << "BrassPlus::~BrassPlus: " << (int64_t)this << std::endl; }
BrassPlusPlus.h
// // BrassPlusPlus.h // TestC++11 // // Created by sai on 8/23/19. // Copyright (c) 2019 sai. All rights reserved. // #ifndef __TestC__11__BrassPlusPlus__ #define __TestC__11__BrassPlusPlus__ #include <iostream> #include "BrassPlus.h" class BrassPlusPlus: public BrassPlus { public: void TestAdd(); void TestVirtualAdd(); ~BrassPlusPlus(); }; #endif /* defined(__TestC__11__BrassPlusPlus__) */
BrassPlusPlus.cpp
// // BrassPlusPlus.cpp // TestC++11 // // Created by sai on 8/23/19. // Copyright (c) 2019 sai. All rights reserved. // #include "BrassPlusPlus.h" void BrassPlusPlus::TestAdd() { std::cout << "BrassPlus::TestAdd" << std::endl; } void BrassPlusPlus::TestVirtualAdd() { std::cout << "BrassPlus::TestVirtualAdd" << std::endl; } BrassPlusPlus::~BrassPlusPlus() { std::cout << "BrassPlusPlus::~BrassPlusPlus: " << (int64_t)this << std::endl; }
main.cpp
// // main.cpp // TestC++11 // // Created by sai on 11/15/16. // Copyright (c) 2016 sai. All rights reserved. // #include <iostream> #include <string> #include "Brass.h" #include "BrassPlusPlus.h" void TestPolymorphic() { Brass b; BrassPlusPlus bp; Brass& b1 = b; Brass& b2 = bp; BrassPlusPlus& bp1 = bp; std::cout << "Reference" << std::endl; b1.TestAdd(); b1.TestVirtualAdd(); b2.TestAdd(); b2.TestVirtualAdd(); bp1.TestAdd(); bp1.TestVirtualAdd(); std::cout << "Pointer" << std::endl; Brass* p1 = &b; Brass* p2 = &bp; BrassPlusPlus* bpp1 = &bp; void* bpp2 = bpp1; Brass& b3 = reinterpret_cast<Brass&>(*bpp2); p1->TestAdd(); p1->TestVirtualAdd(); p2->TestAdd(); p2->TestVirtualAdd(); bpp1->TestAdd(); bpp1->TestVirtualAdd(); b3.TestAdd(); b3.TestVirtualAdd(); } int main(int argc, const char * argv[]) { TestPolymorphic(); return 0; }
output
Reference Brass::TestAdd Brass::TestVirtualAdd Brass::TestAdd Brass::TestVirtualAdd BrassPlus::TestAdd BrassPlus::TestVirtualAdd Pointer Brass::TestAdd Brass::TestVirtualAdd Brass::TestAdd Brass::TestVirtualAdd BrassPlus::TestAdd BrassPlus::TestVirtualAdd Brass::TestAdd Brass::TestVirtualAdd BrassPlusPlus::~BrassPlusPlus: 3221223744 BrassPlus::~BrassPlus: 3221223744 Brass::~Brass: 3221223744 Brass::~Brass: 3221223752 Program ended with exit code: 0
Reference resources
15.5 Type Conversion Operator < C++ Primer Plus > 5th Edition
8.2 Reference Variables <<C++Primer Plus >> 5th Edition
1.3 Object Differences in Deep Exploration of C++ Object Model
13.4 Polymorphic Public Inheritance < < C+ + Primer Plus > 5th Edition