C++ 类和对象 (查漏补缺)

 Inline

内联函数

内联函数是为了替代宏函数而出来的。

下面用宏实现一个ADD宏函数:
C++ 类和对象 (查漏补缺)_第1张图片

为什么这个ADD宏函数要这么写,首先我们来看,假设这样写:

#define ADD(x,y)(x+y)

会有什么问题呢?

宏函数是直接替换了:

3|4+3&4=3|7&3

我们发现因为优先级问题,宏函数的直接替换导致结果偏离了我们的预设。

所以我们需要加括号保证优先级,但是这样太麻烦了,如果是一个ADD函数就不用这么麻烦:

C++ 类和对象 (查漏补缺)_第2张图片

 因为ADD函数不像ADD宏函数那样无脑替换,它会进行先把实参算完再拿过来给形参,把形参算完之后再返回。

但是函数的调用需要建立栈帧,假如我们需要调一万次ADD函数呢?那这个开销就比较大了,我们可以把ADD函数设为内敛函数:C++ 类和对象 (查漏补缺)_第3张图片

普通函数:C++ 类和对象 (查漏补缺)_第4张图片

 内联函数:C++ 类和对象 (查漏补缺)_第5张图片

 内联不会展开,也就是可以把这个函数的功能拿过来直接用,而不用建立栈帧。

成员变量的命名风格

 

下文这样来初始化一个日期类的成员变量

#include
using namespace std;


class Data
{
public:
	void Init(int year,int month,int day)
	{
		year = year;
		month = month;
		day = day;

	}


private:
	int year;
	int month;
	int day;
};
int main()
{

	Data T;
	T.Init(2003,11,29);
	return 0;
}

我们发现并没有初始化上:

 原因:C++ 类和对象 (查漏补缺)_第6张图片

 

这样写加以区分:

#include
using namespace std;


class Data
{
public:
	void Init(int year,int month,int day)
	{
		_year = year;
		_month = month;
		_day = day;

	}


private:
	int _year;
	int _month;
	int _day;
};
int main()
{

	Data T;
	T.Init(2003,11,29);
	return 0;
}

C++ 类和对象 (查漏补缺)_第7张图片

类的实例化

有这样一个日期类:



class Data
{
public:
	void Init(int year,int month,int day)
	{
		_year = year;
		_month = month;
		_day = day;

	}


private:
	int _year;
	int _month;
	int _day;
};

即然有类域,那我们可以这样访问吗?
 

Data::_year;
Data._year;

不可以,因为我们私有的成员变量只是一个声明:

 只有声明是不能直接拿来用的,我们需要定义:

	Data T;

现在定义了一个变量T,就开辟了一块空间,_year,_month,_day的空间也被一把开出来了。

拷贝构造

有如下这么两个类,一个日期类,一个栈类

typedef int DataType;
class Stack
{
public:
	Stack(size_t capacity = 3)
	{
		cout << "Stack()" << endl;
	}

	// s1(s)
	Stack(const Stack& s)
	{
		cout << "Stack(Stack& s)" << endl;
	
	}

	void Push(DataType data)
	{
		// CheckCapacity();
		_array[_size] = data;
		_size++;
	}

	~Stack()
	{
		cout << "~Stack()" << endl;
	}
private:
	// 内置类型
	DataType* _array;
	int _capacity;
	int _size;
};
class Data
{
public:
	void Init(int year,int month,int day)
	{
		_year = year;
		_month = month;
		_day = day;

	}
private:
	int _year;int _month;int _day;
};

现在还有一个fun函数,我们把栈类的值拷贝给这个fun函数:

void fun(Data a)
{

}

int main()
{
	
	Data T;
	T.Init(2003,11,29);
	fun(T);


	return 0;
}

如果我们把日期类拷贝给fun函数就不会蹦:


void fun1(Data s)
{

}


int main()
{
	Data T;
	T.Init(2003,11,29);
	fun1(T);

return 0;
}

如果我们把栈来拷贝给fun函数就会蹦:

void fun2(Stack s)
{

}



int main()
{
   Stack s1;
	
	fun2(s1);

return 0;

}

C++ 类和对象 (查漏补缺)_第8张图片

我们可以画图解析一下:

如图,stack的int*_a是在堆上面开辟的空间,内容存在堆上的,_a指向堆。

fun是stack的浅拷贝,fun的_a也指向同一块地址。

C++ 类和对象 (查漏补缺)_第9张图片

 fun后调用,先结束生命周期,先调用析构。此时就把这块空间释放掉了,那么轮到stack的时候会再次调用析构,会再把这块空间释放一次。

看下面这个图,a和s1的_array都指向堆上的同一块地址:

C++ 类和对象 (查漏补缺)_第10张图片

fun函数先析构:

C++ 类和对象 (查漏补缺)_第11张图片

stack再去析构的时候就会报错,因为stack的_a此时是一个野指针,指向了一块已经被释放了的空间:

 

你可能感兴趣的:(c++,算法,开发语言)