C ++ function semantics

1 Function calling method

1.1 How to call ordinary member functions

We may think that the cost of calling class member functions will be greater than that of calling ordinary functions, but this is not the case. Calling ordinary member functions is similar to global functions. We can debug in VS and view the disassembly code. When the ordinary member function is called, the compiler will pass the this pointer of an object

1.2 How to call virtual functions

EG:

#include<iostream>
using namespace std;

class A
{
public:
	int a;

	virtual void func()
	{

	}

	void test1()
	{
		func();  //由于是用this指针调用func函数,所以会查询虚函数表
	}

	void test()
	{
		A::func();  //这种方式调用func函数不会查询虚函数表
	}
};

int main()
{

	A a = A();

	a.func();  //不会查询虚函数表
	a.test();  //test函数内部调用func函数不会查询虚函数表
	a.test1();  //test1函数内部调用func函数会查询虚函数表

	return 0;
}

1.3 Call of static member function

EG:

#include<iostream>
using namespace std;

class A
{
public:
	int a;

	static void func()
	{
		cout << "静态成员函数" << endl;
	}

	void func1()
	{
		cout << "非静态成员函数" << endl;
	}

	void func2()
	{
		a = 3;
	}
};

int main()
{
	A *a = nullptr;
	a->func(); 
	//这里有疑问,为什莫a为空也可以调用func函数呢?
	  //因为,静态成员函数不需要编译器传入this指针,所以ok

	a->func1();
	 //既然a为空指针,为什莫也可以调用非静态成员函数呢?
	    //因为即使编译器传入了一个this指针,但是在func1中并没有使用this指针,所以即使this指针传入的是空指针也没事

	//a->func2();  //执行这行代码程序异常,由于func2中使用this指针为成员变量a赋值,但是this是一个空指针

	return 0;
}

2 C ++ static and dynamic

2.1 Static and dynamic types

Static type: the type at the time of object definition, which is determined during compilation

Dynamic type: The type of the object target, determined at runtime (along with references and polymorphism)

EG:

#include<iostream>
using namespace std;

class A
{
};
class B : public A
{

};

int main()
{

	A a;  //a的静态类型是A,没有动态类型,因为是直接定义没有使用指针或者引用
	B b;  //b的静态类型是B,没有动态类型
	A* a1;  //a1的静态类型是A,目前没有动态类型,因为a1没有指向任何对象
	A* a2 = new B();  //a2的静态类型是A,动态类型是B

	return 0;
}

2.2 Static binding and dynamic binding

Static binding: the binding is a static type, the corresponding function or property depends on the static type of the object, and occurs at compile time

Dynamic binding: The binding is a dynamic type, and the function or property of a pair depends on the dynamic type of the object, which occurs at runtime

2.3 Static binding of non-virtual functions

EG:

#include<iostream>
using namespace std;

class A
{
public:
	void func()
	{
		cout << "A::func" << endl;
	}
};
class B : public A
{
public:
	void func()
	{
		cout << "B::func" << endl;
	}

};

int main()
{
	B b;
	B* b1 = &b;
	b1->func();  //func是普通成员函数,发生静态绑定,b1的静态类型是B,所以调用B::func

	A* a1 = &b;
	a1->func();  //func是普通成员函数,发生静态绑定,b1的静态类型是A,所以调用A::func
	return 0;
}

2.4 Dynamic binding of virtual functions

EG:

#include<iostream>
using namespace std;

class A
{
public:
	virtual void func()
	{
		cout << "A::func" << endl;
	}
};
class B : public A
{
public:
	virtual void func()
	{
		cout << "B::func" << endl;
	}

};

int main()
{
	B b;
	B* b1 = &b;
	b1->func();  //func是虚函数,发生动态绑定,b1的动态类型是B,所以调用B::func

	A* a1 = &b;
	a1->func();  //func是虚函数,发生动态绑定,b1的动态类型是B,所以调用B::func
	return 0;
}

2.5 Default parameter pits in virtual functions

If there is a default parameter in the virtual function, then the value of this default parameter is static binding

EG:

#include<iostream>
using namespace std;

class A
{
public:
	virtual void func(int i = 0)
	{
		cout << "A::func  i:" << i << endl;
	}
};
class B : public A
{
public:
	virtual void func(int i = 1)
	{
		cout << "B::func  i:" << i << endl;
	}

};

int main()
{
	B b;
	B* b1 = &b;
	b1->func();  //调用B::func,打印的i的值是1

	A* a1 = &b;
	a1->func();  //调用B::func,打印的i的值是0(注意)
	return 0;
}

3 Exploration of virtual functions in multiple inheritance

3.1 Call of destructor in virtual base class inheritance

EG:

#include<iostream>
using namespace std;

class A
{
public:
	 ~A()
	{
		cout << "A::~A" << endl;
	}
};

class B :public A
{
public:
	 ~B()
	{
		cout << "B::~B" << endl;
	}
};

class A1
{
public:
	~A1()
	{
		cout << "A1::~A1" << endl;
	}
};

class B1 :public A1
{
public:
	virtual ~B1()
	{
		cout << "B1::~B1" << endl;
	}
};


class A2
{
public:
	virtual ~A2()
	{
		cout << "A2::~A2" << endl;
	}
};

class B2 :public A2
{
public:
	~B2()  //由于继承的A2有一个虚析构函数,所以本类中的析构函数也是虚函数
	{
		cout << "B2::~B2" << endl;
	}
};

int main()
{
	//A* a = new B();
	//delete a;  //因为析构函数不是虚函数,所以发生静态绑定,只会调用A的析构函数,但是a的动态类型是B,此时因为B的this指针和A的this指针指向同一地方,在VS中不会报错,但是没有调用派生类析构函数终究是不严谨的

	//A1* a1 = new B1();
	//delete a1;  //程序在VS中会报错,因为A1的this指针和B1的this指针不指向同一位置

	A2* a2 = new B2();
	delete a2;  //程序正常执行,符合预期,所以在发生有虚函数的继承时,应当给基类添加虚析构函数

	return 0;
}

In inheritance, as long as the destructor of the subclass is called, even if the memory is successfully released, because the compiler will call the destructor of the base class in the destructor of the subclass, just like recursion, until the top-level base The destructor of the class is called before it returns layer by layer

3.2 Release the error caused by the second base class without virtual destructor

EG:

#include<iostream>
using namespace std;

class A1{};

class A2{};

class B :public A1, public A2{};

int main()
{
	A2 * a2 = new B();
	delete a2;  //由于返回的是B类实例偏移后的指针,所以不是对象首地址指针,调用delete会发生异常

	//解决办法1
	//将a2转换为B类

	//解决办法2
	//给A2类添加一个虚析构函数

	return 0;
}

 

 

 

 

 

 

 

 

Published 123 original articles · praised 31 · 90,000 views +

Guess you like

Origin blog.csdn.net/qq_40794602/article/details/103836567