[C + +] analysis of polymorphic common exercises to see if you can't

1, Summary

Static polymorphism: function overloading, calling the same function and passing different parameters will have different behaviors
Dynamic polymorphism: when calling virtual functions, different objects will have different behaviors / forms

Conditions for polymorphism:
a. Override the virtual function of the parent class in the subclass.
b. The overridden virtual function must be called by the pointer or reference of the parent class.

Rewriting of virtual functions:
a. Both parent and child classes must be virtual functions
b. The function name, parameter and return value must be the same

Exceptions:
a. Covariance (pointer or reference to parent and child classes)
b. The destructor needs special treatment, because the parent class pointer may point to the object of the subclass, so the destructor of the subclass object needs to be called
c. Virtual functions in subclasses can be rewritten without virtual

The virtual table pointer of the object is generated only in the initialization list of the constructor, but the virtual function table is generated during compilation. Reason: dynamic generation during operation usually requires space and needs to be applied on the heap.



2, Exercises

Why can't the following code run?

class A
{
public:
	virtual void func1()
	{}

	int a = 0x10;
};
class B:virtual public A
{
public:
	virtual void func1()
	{}
	int b = 0x20;
};
class C :virtual public A
{
public:
	virtual void func1()
	{}
	int c = 0x30;
};
class D:public B,public C
{
public:
	/*virtual void func1()
	{}*/
	int d = 0x40;
};

int main()
{
	D d;
	return 0;
}

Analyze its object model. Since B and C virtually inherit A, there will be only one A in D's object model, but both B and C rewrite A, resulting in two different implementation versions of func1 in D's view. Therefore, if func1 is not rewritten in D, it will lead to compilation errors. However, if func1 is not rewritten in B and C, there will be two copies of func1 at D, but they are the same. At this time, there will be no compilation error.

The function of the first four bytes of the pointer content of the virtual base table:
It is used to calculate a distance from the virtual table pointer to the virtual base table pointer.
In the following code, let's analyze the object model of d.

class A
{
public:
	virtual void func1()
	{}

	int a = 0x10;
};
class B:virtual public A
{
public:
	virtual void func1()
	{}
	virtual void func2()
	{}
	int b = 0x20;
};
class C :virtual public A
{
public:
	virtual void func1()
	{}
	virtual void func2()
	{}
	int c = 0x30;
};
class D:public B,public C
{
public:
	virtual void func1()
	{}
	virtual void func2()
	{}
	int d = 0x40;
};

int main()
{
	D d;
	
	return 0;
}

Through the memory window and monitoring window, we can know that the first address of Part B in the d object is the pointer to the virtual function table, while the second field points to the virtual base table. In the previous blog, the first field of the virtual base table has always been 0x00 00, but now it is 0xff FC, that is - 4, Four bytes up from the address of the virtual base table pointer is exactly the virtual function table pointer. Therefore, the first field in the virtual base table is used to get the position of the virtual function table.


choice question

  1. Which of the following object-oriented methods can make you rich ()
    A: Inheritance B: encapsulation C: polymorphism D: abstraction

A. Inheritance is a kind of reuse

  1. () is a mechanism in object-oriented programming language. This mechanism realizes that the definition of the method is independent of the specific object, while the call to the method can be associated with the specific object.
    A: Inheritance B: template C: self reference of object D: dynamic binding

D. The pointer or reference of the parent class can point to the virtual function table of the child class

  1. What is wrong with the following statement about inheritance and composition in object-oriented design? ()
    A: Inheritance allows us to override the implementation details of the parent class. The implementation of the parent class is visible to the child class. It is a kind of static reuse, also known as
    White box multiplexing
    B: The combined objects do not need to care about their implementation details. The relationship between them is determined at runtime. It is a kind of dynamic reuse and
    Black box multiplexing
    C: Using inheritance first rather than composition is the second principle of object-oriented design
    D: Inheritance can enable subclasses to automatically inherit the interface of the parent class, but in the design pattern, it is considered to be a manifestation that destroys the encapsulation of the parent class

C. The combination is preferred. Inheritance is the static reuse of the parent class, and the combination is the dynamic reuse.

  1. The following statements about pure virtual functions are correct: (A) classes declaring pure virtual functions cannot instantiate objects; (B) classes declaring pure virtual functions are virtual base classes; (C) subclasses must implement pure virtual functions of base classes; (D) pure virtual functions must be empty functions

A. C subclass can not implement pure virtual functions, but it cannot instantiate objects.

  1. The correct description of virtual function is () A: the virtual function of the derived class has different number and type of parameters from the virtual function of the base class. B: the inline function cannot be A virtual function. C: the derived class must redefine the virtual function of the base class. D: the virtual function can be A static function

B. Inline is a suggestion for the compiler. After declaring virtual, the inline attribute will be ignored, because the inline function has no address and is expanded where it is called. Virtual functions should be placed in the virtual function table. Note: you can run under vs2013 and liunx.

  1. A: a class can only have one virtual table. B: there are virtual functions in the base class. If the virtual functions of the base class are not rewritten in the subclass, the subclass and the base class share the same virtual table. C: the virtual table is dynamically generated during operation. D: different objects of a class share the virtual table of that class

D. Dynamic generation in C usually requires space and needs to be applied on the heap. So we can guess that it was generated during compilation.

  1. Suppose there is a virtual function in class A, B inherits from a, B rewrites the virtual function in a, and there is no virtual function defined, then ()
    A: The first four bytes of class a objects store virtual table addresses, while the first four bytes of class B objects are not virtual table addresses. B: the first four bytes of class a objects and class B objects store virtual base table addresses
    C: The virtual table addresses stored in the first four bytes of class A and class B objects are the same. D: the number of virtual functions in class A and class B virtual tables is the same, but class A and class B do not use the same virtual table

D. The virtual function table is polymorphic, and the virtual base table is the member variable in the virtual inherited superclass

  1. What is the output of the following program? ()
#include<iostream>
using namespace std;
class A{
public:
	A(char *s) { cout << s << endl; }
	~A(){}
};
class B :virtual public A
{
public:
	B(char *s1, char*s2) :A(s1) { cout << s2 << endl; }
};
class C :virtual public A
{
public:
	C(char *s1, char*s2) :A(s1) { cout << s2 << endl; }
};
class D :public B, public C
{
public:
	D(char *s1, char *s2, char *s3, char *s4) :C(s1, s3), B(s1, s2), A(s1)
	{
		cout << s4 << endl;
	}
};
int main() {
	D *p = new D("class A", "class B", "class C", "class D");
	delete p;
	return 0;
}

Answer: A
First, the exclusion method. We declare that the order of inheritance is the order of initialization. Note that this is not the order of initialization list, so we can exclude CD, because B should be in front of C. Then we need to initialize the parent class first, and A is in front. And the compiler will optimize, and each object will be initialized only once.

9. The following results

class A
{
public:
	A(int a)
		:_a1(a)
		, _a2(_a1)
	{}

	void Print() {
		cout << _a1 << " " << _a2 << endl;
	}
private:
	int _a2;
	int _a1;
};
int main() {
	A aa(1);
	aa.Print();
	return 0;
}

Answer: output 1 random value
Because the order of member variable declaration is the order of initializing the list, he will go first_ a2(_a1) then go_ a1(a).

  1. Pointer offset in multi inheritance? The following statement is correct ()
class Base1 { public: int _b1; };
class Base2 { public: int _b2; };
class Derive : public Base1, public Base2 { public: int _d; };
int main(){
 Derive d;
 Base1* p1 = &d;
 Base2* p2 = &d;
 Derive* p3 = &d;
 return 0;
}

A: p1 == p2 == p3 B: p1 < p2 < p3 C: p1 == p3 != p2 D: p1 != p2 != p3


Choose C

  1. What is the output of the following program ()
class A
{
public:
 virtual void func(int val = 1){ std::cout<<"A->"<< val <<std::endl;}
 virtual void test(){ func();}
};
class B : public A
{
public:
 void func(int val=0){ std::cout<<"B->"<< val <<std::endl; }
};
int main(int argc ,char* argv[])
{
 B*p = new B;
 p->test();
 return 0;
}
A: A->0 B: B->1 C: A->1 D: B->0 E: Compilation error F: None of the above is correct

Choose B
Because there is no rewriting of test in B, then calling the parent class test(), calling func in test, this pointer is B type, B and rewriting func, rewriting is an interface inheritance, rewriting as long as the parameters are satisfied, the function name returns the same value, and the default parameter will be used by the parent class, so the final print is B->1.
Ordinary functions implement inheritance.
Virtual function inheritance is an interface inheritance.

class A
{
public:
	virtual void func(int val = 1)
	{
	}

	void test()
	{ 
	}
};


// A compilation error B operation crash C normal operation
int main()
{
	// 1, 
	A* p1 = nullptr;
	p1->func();

	// 2, 
	A* p2 = nullptr;
	p2->test();

	return 0;
}

1b, 2C. The reason is that ordinary member functions are placed in the code segment. We don't need the dereference behavior to call, so the second one won't make an error, and the first one will access the first four bytes of the object pointed to by p1 because the two conditions of polymorphism are met, so it will report an error.

Question and answer:

Can static members be virtual functions?
No, the static member function does not have this pointer, applicable type: the calling method of the member function cannot access the virtual function table,

Can a constructor be a virtual function?
Do constructors need to be polymorphic? It doesn't make sense because when we instantiate a subclass object, we also need to call the constructor of the parent class. The virtual function table of the object is initialized at compile time, and the virtual table pointer is generated after passing through the initialization list of the constructor at run time.
The virtual table pointer of the object is initialized only in the constructor initialization list. If the constructor is made into a virtual function, the object needs a virtual table pointer to call the constructor, which is self contradictory. Therefore, when the constructor of the parent class is set as a virtual function, a compilation error will be reported directly.

Do destructors need virtual functions?
Yes, because when we delete (pointer), we don't know whether the object pointed to by this pointer is a parent object or a child object. Through polymorphism, we can dynamically detect and release.

Is it faster for objects to access ordinary functions or virtual functions??
A: first of all, if it is an ordinary object, it is as fast. If it is a pointer object or a reference object, the ordinary function called is fast. Because it constitutes polymorphism, it is necessary to look up the virtual function table when calling the virtual function at runtime.
Object calls cannot be polymorphic

Little knowledge

1. The template is polymorphic at compile time. We can see through disassembly that it will jump to the corresponding function after call ing at run time.

2. The method called by the parent object is always the parent method!

3. Embodiment of interface inheritance
4. The reason why the static member function cannot be set as a virtual function is that the static member function does not have this pointer. Without this pointer, you can't get the virtual table and realize polymorphism.

5. Assuming the rewriting is successful, can polymorphism be realized through pointer or reference?
wrong! It must be a pointer or reference to the parent class.

6. When both polymorphism and combination can be used, combination is recommended, because polymorphic calls have additional overhead, including virtual function table pointer, virtual function table, runtime resolution, etc.

7. A friend function cannot be set as a virtual function because it does not belong to a member function.

summary

This concludes the section on polymorphism.

Keywords: C++ Back-end

Added by fat creative on Sat, 12 Feb 2022 06:33:53 +0200