C + + virtual functions and polymorphism

Keywords: C++ Back-end

Virtual functions and virtual function tables

  1. Virtual function: a member function decorated with virtual
  2. Impact of virtual function on class: add a pointer, 32-bit 4 bytes, 64 bit 8 bytes
  3. Virtual function table: a pointer that stores the first addresses of all virtual functions

Virtual functions and polymorphisms

Polymorphism: different results from the same behavior (call)

Principle of necessity:

  • The parent class must have a virtual function
  • Subclasses must adopt public inheritance
  • Pointer usage must exist
    #include<iostream>
    using namespace std;
    class Ins{
    public:
    	void func(){
    		cout << "Hello!" << endl;
    	}
    	virtual void func1(){
    		cout << "He's good!" << endl;
    	}
    protected:
    };
    class Owe:public Ins
    {
    public:
    	void func(){
    		cout << "You are not good!" << endl;
    	}
    	void func1(){
    		cout << "He's not good!" << endl;
    	}
    protected:	
    };
    int main(){
    	//There is virtual to see the object type, not virtual to see the pointer type
    	Ins* i = new Owe;
    	i->func();//Not a virtual function
    	i->func1();//virtual function
    	i = new Ins;
    	i->func1();
    	while (1);
    	return 0;
    }

The output is as shown in the figure: 

The role of polymorphism: it can reduce the modification based on the source code, but increase the code to achieve the desired effect

Pure virtual function and ADT

Pure virtual function: it is a virtual function without function body

Function: perform ADT (abstract data type) process

How to write in class:

virtual void function()=0;

Abstract class: a class with at least one pure virtual function is called an abstract class  

  • Abstract classes cannot construct objects
  • Abstract classes can construct object pointers
    #include<iostream>
    using namespace std;
    class stack{
    public:
    	virtual void push(int data) = 0;
    	virtual void pop() = 0;
    	virtual int top()const = 0;
    	virtual bool empty()const = 0;
    	virtual int size()const = 0;
    protected:
    
    };
    //To create an object, a subclass must override the pure virtual function of the parent class
    //ADT procedure: mandatory. All subclass override functions must be the same as the parent class
    class arrayStack :public stack{
    public:
    	void push(int data){};
    	void pop(){};
    	int top()const{ return 1; };
    	bool empty()const { return true; };
    	int size()const{ return 1; };
    protected:
    };
    class listStack :public stack{
    public:
    	void push(int data){};
    	void pop(){};
    	int top()const{ return 1; };
    	bool empty()const { return true; };
    	int size()const{ return 1; };
    protected:
    };
    void testStack(stack* p){
    	p->push(0);
    	while (!p->empty()){
    		cout << p->top() << endl;
    		p->pop();
    	}
    }
    int main(){
    	testStack(new arrayStack);
    	testStack(new listStack);
    	while (1);
    	return 0;
    }

pure virtual destructor

When initializing the parent class pointer with a subclass object, the parent class needs to write a virtual destructor to release memory

#include<iostream>
using namespace std;
class parent{
public:	
	//virtual ~parent(){
	//	Cout < < parent class < < endl;
	//}
protected:
};
class kid:public parent{
public:
	~kid(){
		cout << "Subclass" << endl;
}
protected:
};
int main(){
	parent* ptr = new kid;
	delete ptr;
	ptr = nullptr;
	while (1);
	return 0;
}

  final and override

final and override: final: override is prohibited (only used in inheritance). It can only be used for virtual functions and. Subclasses cannot have functions with the same name. Override is forced to override, identify the role, and check whether there is a current virtual function in the parent class

class parent{
public:
	virtual void func() final{}
	virtual void func1(){}
protected:
};
class child:public parent{
public:
	//The function void func() {} with the same name as the parent cannot be used;
	void func1()override{}//If the parent class does not have a virtual function with the same name, an error will be reported
protected:
};

C + + type conversion

Format:   keyword  _ Cast < type to convert > (target to convert)

  • const_cast: function: 1. Remove const attribute (provide an interface operation const attribute)     2. Add const attribute
        int num=1;
    	const int&p = num;
    	int&pp = const_cast<int&>(p);//Remove const attribute
    	int a = 5;
    	int*ptr = &a;
    	const int*pr = const_cast<const int*>(ptr);//Add const attribute, use less, do not write const_cast can also be implicitly converted, that is: const int*pr=ptr;
    

  • static_cast:

1. Basic data type conversion

2. Convert null pointer to corresponding type pointer

3. Convert any type variable to void type

4. Conversion between objects of base class and derived class:

      Perform uplink conversion (from child to parent, pointer or reference conversion)

      Downstream conversion (parent to child, pointer or reference conversion)

Note: static_cast cannot be used to remove const

  • dynamic_cast:

1. Uplink conversion (same as static_cast)

2. Downlink conversion (dynamic is safer)

#include<iostream>
#include<string>
using namespace std;
class parent{
public:
	virtual void print(){ cout << str << endl; }
protected:
	string str = "ILoveYou!";
};
class child:public parent{
public:
	void print(){ cout << str1 << endl; }
protected:
	string str1 = "Hello!";
};
int main(){
	parent* p=new parent;
	child* q=new child;
	//Uplink conversion
	parent* l = static_cast<parent*>(q);
	parent* u = dynamic_cast<parent*>(q);
	l->print();
	u->print();
	//Downlink conversion
	child* h = static_cast<child*>(p);
	child* k = dynamic_cast<child*>(p);//dynamic can check whether polymorphism exists in the parent class
	if (k!=nullptr)
		k->print();
	h->print();
	while (1);
	return 0;
}

3. Cross conversion (multi inheritance)

#include<iostream>
using namespace std;
class A{
public:
	virtual void print(){ cout << 'A'<<endl ;}
protected:
};
class B{
public:
	virtual void print(){ cout << 'B' << endl; }
protected:
};
class C:public A,public B{
public:
	void print(){ cout << 'C' << endl; }
protected:
};
int main(){
	//Cross conversion
	A* a = new C;
	B* b = dynamic_cast<B*>(a);
	b->print();
	while (1);
	return 0;
}
  • reinterpret_cast: convert a number to a pointer and a pointer to a number
    #include<iostream>
    using namespace std;
    int Max(int a, int b)
    {
       return a > b ? a : b;
    }
    int main(){
    	int num = reinterpret_cast<int>(Max);
    	cout << num << endl;
    	cout << Max << endl;
    	auto p = reinterpret_cast<int(*)(int a, int b)>(num);
    	cout << p(1, 2) << endl;
    	while (1);
    	return 0;
    }

Posted by solee on Sun, 05 Dec 2021 20:35:40 -0800