[C++] Virtual function and polymorphism

polymorphism

Polymorphism is one of the important features of object-oriented programming, which means that when the same message is sent and received by different types of objects, it may lead to completely different behaviors. Polymorphic implementation: function overloading, operator overloading, templates, virtual functions.

Static Binding vs. Dynamic Binding

Static binding: The binding process occurs in the compilation phase, and the function to be called has been determined during the compilation phase.
Dynamic binding: the binding process is executed when the program is running, and the function to be called is determined when the program is running.

virtual function

The concept of virtual function: a member function labeled with the keyword virtual in the base class.
Definition of virtual function:

virtual 函数类型 函数名称(参数列表);

If a function is declared virtual in the base class, it will be virtual in all derived classes. Dynamic binding can only be induced through base class pointers or calls to virtual functions. Virtual functions cannot be declared static.

#include <iostream>
using namespace std;

class Base
{
    
    
public:
    virtual void Fun1()
    {
    
    
        cout << "Base::Fun1 ..." << endl;
    }
    virtual void Fun2()
    {
    
    
        cout << "Base::Fun2 ..." << endl;
    }
    void Fun3()
    {
    
    
        cout << "Base::Fun3 ..." << endl;
    }
};

class Derived :public Base
{
    
    
public:
    virtual void Fun1()

    {
    
    
        cout << "Derived::Fun1 ,,," << endl;
    }
    virtual void Fun2()
    {
    
    
        cout << "Derived::Fun2 ,,," << endl;
    }
    void Fun3()
    {
    
    
        cout << "Derived::Fun3 ..." << endl;
    }
};

int main()
{
    
    
    Base* p;
    Derived d;

    p = &d;
    p->Fun1();//Fun1是虚函数,基类指针指向派生类对象,调用的是派生类对象的虚函数
    p->Fun2();
    p->Fun3();//Fun3非虚函数,根据p指针实际类型来调用相应类的成员函数
    return 0;
}

virtual destructor

When do you need a virtual destructor? While you may delete a derived class object through a base class pointer, if you plan to allow others to call the object's destructor through the base class pointer (it is normal to do so through delete), and the destructed object has important analysis Objects of the derived class of the constructor need to make the destructor of the base class a virtual function.

#include <iostream>
using namespace std;

class Base
{
    
    
public:
    virtual void Fun1()
    {
    
    
        cout << "Base::Fun1 ..." << endl;
    }
    virtual void Fun2()
    {
    
    
        cout << "Base::Fun2 ..." << endl;
    }
    void Fun3()
    {
    
    
        cout << "Base::Fun3 ..." << endl;
    }
    Base()
    {
    
    
        cout << "Base ..." << endl;
    }
    virtual ~Base()
    {
    
    
        cout << "~Base ..." << endl;
    }
};

class Derived :public Base
{
    
    
public:
    virtual void Fun1()

    {
    
    
        cout << "Derived::Fun1 ,,," << endl;
    }
    virtual void Fun2()
    {
    
    
        cout << "Derived::Fun2 ,,," << endl;
    }
    void Fun3()
    {
    
    
        cout << "Derived::Fun3 ..." << endl;
    }
    Derived()
    {
    
    
        cout << "Derived ..." << endl;
    }
    //基类析构函数为虚函数   派生类不加virtual也为虚函数
    //如果一个类要作为多态基类,要将析构函数定义成虚函数
    virtual ~Derived()
    {
    
    
        cout << "~Derived ..." << endl;
    }
};

int main()
{
    
    
    Base* p;
    p = new Derived;

    p->Fun1();
    delete p;
    return 0;
}

vtable pointer

The dynamic binding of virtual functions is realized through virtual tables. The first 4 bytes of the class containing the virtual function store the pointer to the virtual table.

object slicing and virtual functions

#include <iostream>
using namespace std;

class CObject
{
    
    
public:
    virtual void Serialize()
    {
    
    
        cout << "CObject::Serialize ..." << endl;
    }
};

class CDocument : public CObject
{
    
    
public:
    int data1_;
    void func()
    {
    
    
        cout << "CDocument::func ..." << endl;
        Serialize();
    }
    void Serialize()
    {
    
    
        cout << "CDocument::Serialize ..." << endl;
    }
    CDocument()
    {
    
    
        cout << "CDocument()" << endl;
    }
    CDocument(const CDocument& other)
    {
    
    
        cout << "CDocument(const CDocument& other)" << endl;
    }
};

class CMyDoc : public CDocument
{
    
    
public:
    int data2_;
    void Serialize()
    {
    
    
        cout << "CMyDoc::Serialize ..." << endl;
    }
};

int main()
{
    
    
    CMyDoc mydoc;
    CMyDoc* pmydoc = new CMyDoc;
    cout << "#1 testing" << endl;
    mydoc.func();

    cout << "#2 testing" << endl;
    ((CDocument*)(&mydoc))->func();  

    cout << "#3 testing" << endl;
    pmydoc->func();

    cout << "#4 testing" << endl;
    ((CDocument)mydoc).func();//mydoc对象强制转换为CDocument对象  向上转型  完全将派生类对象转化成了基类对象
    return 0;
}

overload、overwrite、override

Characteristics of member functions that are overloaded:

  • the same scope (in the same class);
  • The function names are the same;
  • The parameters are different;
  • The virtual keyword is optional.

Overriding means that the derived class function covers the base class function, and the characteristics are:

  • Different scopes (in derived and base classes respectively);
  • The function names are the same;
  • The parameters are the same;
  • Base class functions must have the virtual keyword.

Redefinition (derived and base classes)

  • Different scopes (in derived and base classes respectively);
  • The function name and parameters are the same, without the virtual keyword;
  • The function names are the same, but the parameters are different, virtual is optional. ·

pure virtual function

The premise of virtual function to realize polymorphism. A common interface needs to be defined in the base class, and the interface should be defined as a virtual function. What if the interfaces of the base class cannot be implemented, define these interfaces as pure virtual functions. A meaningful virtual function definition cannot be given in the base class. At this time, it can be described as a pure virtual function, and its definition is left to the derived class. Pure virtual functions do not need to be implemented. Define a pure virtual function:

class 类名{
    
    
	virtual 返回值类型 函数名(参数表) = 0}

abstract class

Abstract classes are declared for the purpose of abstraction and design, organize relevant data and behaviors in an inheritance hierarchy, and ensure that derived classes have the required behaviors. For functions that cannot be implemented temporarily, they can be declared as pure virtual functions and left to derived classes to implement. Abstract classes can only be used as base classes, objects of abstract classes cannot be declared, constructors cannot be virtual functions, and destructors can be virtual functions. Abstract classes cannot be used to directly create object instances, and pointers and references to abstract classes can be declared. Runtime polymorphism is supported using pointers to abstract classes. The pure virtual function in the base class must be implemented in the derived class, otherwise it will be regarded as an abstract class.

Advantages of polymorphism

  • Polymorphism helps to better abstract programs. The control module can focus on dealing with general problems. Specific operations are handed over to specific objects to do.

  • Polymorphism helps to improve the scalability of the program. It is possible to separate the control module from the object being operated. A new object of a defined class can be added and the object can be managed. A new object of a new class (a class derived from an existing class) can be added and the object can be managed.

virtual destructor

The destructor can be declared as a virtual function, and the delete base class pointer program will determine the destructor to be called according to the type of the object pointed to by the base class pointer. The destructor of the base class is a virtual function, and the destructor of all derived classes is a virtual function. Constructors must not be virtual. If you want to manipulate dynamic objects of classes with inheritance relationships, it is best to use virtual destructors. Especially when the destructor needs to complete some meaningful operations such as freeing memory, the destructor can also be pure virtual.

For a class without any interface, if you want to define it as an abstract class, you can only declare the virtual destructor as pure virtual. Usually, the pure virtual function does not need to be implemented in the base class, except for pure virtual analysis. The constructor should be given an implementation (just give an empty implementation).

#include <iostream>
#include <vector>
using namespace std;

class Shape
{
    
    
public:
    virtual void Draw() = 0;
    virtual ~Shape() {
    
    };
};

class Circle :public Shape
{
    
    
public:
    void Draw()
    {
    
    
        cout << "Circle::Draw() ..." << endl;
    }
    ~Circle()
    {
    
    
        cout << "~Circle ..." << endl;
    }
};


class Square :public Shape
{
    
    
public:
    void Draw()
    {
    
    
        cout << "Square::Draw() ..." << endl;
    }
    ~Square()
    {
    
    
        cout << "~Square ..." << endl;
    }
};

class Rectangle :public Shape
{
    
    
public:
    void Draw()
    {
    
    
        cout << "Rectangle::Draw() ..." << endl;
    }
    ~Rectangle()
    {
    
    
        cout << "~Rectangle ..." << endl;
    }
};

void DrawAllShapes(const vector<Shape*>& v)
{
    
    
    vector<Shape*>::const_iterator it;
    for (it = v.begin(); it != v.end(); ++it)
    {
    
    
        (*it)->Draw();
    }
}

void DeleteAllShapes(const vector<Shape*>& v)
{
    
    
    vector<Shape*>::const_iterator it;
    for (it = v.begin(); it != v.end(); ++it)
    {
    
    
        delete (*it);
    }
}

class ShapeFactory
{
    
    
public:
    static Shape* CreateShape(const string& name)
    {
    
    
        Shape* ps = 0;
        if (name == "Circle")
        {
    
    
            ps = new Circle;
        }
        else if (name == "Square")
        {
    
    
            ps = new Square;
        }
        else if (name == "Rectangle")
        {
    
    
            ps = new Rectangle;
        }
        return ps;
    }
};
int main()
{
    
    
    //Shape s; ERROR,不能实例化抽象类
    vector<Shape*> v;
    Shape* ps;
    /*ps = new Circle;
    v.push_back(ps);
    ps = new Square;
    v.push_back(ps);
    ps = new Rectangle;
    v.push_back(ps);*/

    ps = ShapeFactory::CreateShape("Circle");
    v.push_back(ps);
    ps = ShapeFactory::CreateShape("Square");
    v.push_back(ps);
    ps = ShapeFactory::CreateShape("Rectangle");
    v.push_back(ps);

    DrawAllShapes(v);
    DeleteAllShapes(v);
    return 0;
}

Guess you like

Origin blog.csdn.net/weixin_43912621/article/details/131203755