[C/C++] [Intermediate] [What's the difference between reference and pointer in polymorphism]

Keywords: Attribute

scene

  1. In developing C++ programs, polymorphic references and pointers are often used. What's the difference between them?

  2. When will polymorphic references and pointers call virtual function tables and when not?

  3. Polymorphic references and pointers are methods of subclasses or superclasses of calls?

Explain

Reference variable

  1. 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.

  2. 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;

  3. 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

  1. 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.

  2. 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.

  3. References and pointers call virtual function tables only when methods are declared as virtual functions.

  4. 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.

  5. 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.

  6. 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

  1. Reference is not an address, and pointers often represent an address.

  2. A reference must be an alias for a defined object, not NULL.

  3. Class references are commonly used. As symbols for calling attribute methods, pointers need to use - >.

  4. 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

Posted by deltatango5 on Fri, 23 Aug 2019 01:53:06 -0700