【C++】类和对象(上)

5a2585dded9b416fb4ea58637b42ed39.png

  Yan-英杰的主页

悟已往之不谏 知来者之可追  

C++程序员,2024届电子信息研究生


目录

宏函数

内联函数

面向过程和面向对象的初步认识

        面向过程:更注重过程

        面向对象:更注重结果

类的引用

this指针

        this指针存在哪里?

C语言和C++实现栈语言的对比

        C语言实现

        C++实现


宏函数

        

        优点:不用创造栈帧,提高了调用效率

        缺点:复杂容易报错,可读性差,无法调试

内联函数

        1.Func不是inline,合计多少行指令

                10000+50

        2.Func是inline,合计多少行指令。10000*50

        可执行程序变大

        适用于短小频繁调用的函数,inlink对于编译器只是一个建议,是否成为inlink需要编译器自己决定,如果函数过长的时候,inlink不起作用,防止代码膨胀,同时语言的发展,必须向前兼容,之前的代码无法进行更改,一旦更改之后,有的人的代码或者程序会出现大批量BUG。

        NULL实际上是宏函数,#define NULL 0

        内联函数,声明和定义不能分开

inline int Add(int x,int y)
{
	return (x + y) * 10;
}


int main()
{
	for (int i = 0; i< 10000; i++)
	{
		printf("%d \n",i);
	}

}

宏函数和内联函数适用于短小的频繁调用的函数

面向过程和面向对象的初步认识

        面向过程:更注重过程

        例如:洗衣服

        面向对象:更注重结果

        例如: 洗衣服 

        将一件事情拆成不同的对象,靠对象之间进行交互完成。

类的引用

                一般情况下,成员变量是私有的,而方法是公有的,大部分的公司为了区分成员变量和参

数进行区分,会在成员变量进行前加杠或者后加杠

struct Stack
{
public:
	//成员函数
	void Init(int defaultCapacity = 4)
	{
		a = (int*)malloc(sizeof(int)* capacity);
		if (nullptr == a)
		{
			perror("malloc内容空间申请失败");
			return;
		}
		capacity = defaultCapacity;
		top = 0;
	}

	void Push(int x)
	{
		a[top++] = x;
	}

	void Destory()
	{
		free(a);
		a = nullptr;
		top = capacity;
	}

	//成员变量
private:
	int* a;
	int _top;
	int _capacity;
};

int main()
{
	struct Stack st1;
	st1.Init(20);
	Stack st2;
	st2.Init();
	st2.Push(1);
	st2.Push(2);
	st2.Push(3);
	st2.Push(4);
	st2.Destory();

	return 0;
}

        面向对象的三大特性:封装、继承、多态

       封装:将数据和操作数据的方法进行有机结合,隐藏对象的属性和实现细节,仅对外公开接口

和对象进行交互。

        封装本质是一种管理,让用户更方便使用类。   比如:对于电脑这样一个复杂的设备,提供给

用户的就只有开机键,通关键盘输入 、显示器、USB插孔,让用户和计算机进行交换,完成日常

事务。但实际上电脑真正工作的确实CPU、显卡、内存等硬件

        对于计算机使用者而言,不用关心内部核心插件,比如主板上线路是如何布局的,CPU内部

是如何设计的等,用户只需要知道,怎么开机、怎么通过键盘和鼠标与计算机进行交互即可。因为

计算机厂商在出厂时,在外部套上壳子,将内部实现隐藏起来。

        

//类中仅有成员函数
class A2
{
public:
	void f2() {}
};

//类中什么都没有


class A3
{

};
int main()
{

    //没有成员变量的类对象,需要1byte,是为了占位,表示对象存在
    //不存储有效数据
	cout << sizeof(A2) << endl;
	cout << sizeof(A3) << endl;
}

        

this指针

        this不能在形参和实参显示传递,但是可以函数内部显示使用

        this指针存在哪里?

        this指针是个形参,是实参的临时拷贝,存储在栈空间内,作为栈帧的一部分

        vs下面对this指针传递,进行优化,对象地址是放在ecx,ecx存储this指针的值

        

        this指针的特性
         1. this指针的类型:类类型* const,即成员函数中,不能给this指针赋值。
        2. 只能在“成员函数”的内部使用
        3. this指针本质上是“成员函数”的形参,当对象调用成员函数时,将对象地址作为实参传递给this形参。所以对象中不存储this指针
        4. this指针是“成员函数”第一个隐含的指针形参,一般情况由编译器通过ecx寄存器自动传递,不需要用户传递

        this指针是空的,虽然函数内部调用了this指针,但是未对其进行解引用,所以并未发生报

错,正常运行 

        this指针是空的,但是函数内访问_a,本质是this->a,而a里面是空的,所以运行时发生崩溃

C语言和C++实现栈语言的对比

        

        C语言实现

        

typedef int DataType;
typedef struct Stack
{
	DataType* array;
	int capacity;
	int size;
}Stack;
void StackInit(Stack* ps)
{
	assert(ps);
	ps->array = (DataType*)malloc(sizeof(DataType) * 3);
	if (NULL == ps->array)
	{
		assert(0);
		return;
	}
	ps->capacity = 3;
	ps->size = 0;
}
void StackDestroy(Stack* ps)
{
	assert(ps);
	if (ps->array)
	{
		free(ps->array);
		ps->array = NULL;
		ps->capacity = 0;
		ps->size = 0;
	}
}
void CheckCapacity(Stack* ps)
{
	if (ps->size == ps->capacity)
	{
		int newcapacity = ps->capacity * 2;
		DataType* temp = (DataType*)realloc(ps->array,
			newcapacity * sizeof(DataType));
		if (temp == NULL)
		{
			perror("realloc申请空间失败!!!");
			return;
		}
		ps->array = temp;
		ps->capacity = newcapacity;
	}
}
void StackPush(Stack* ps, DataType data)
{
	assert(ps);
	CheckCapacity(ps);
	ps->array[ps->size] = data;
	ps->size++;
}
int StackEmpty(Stack* ps)
{
	assert(ps);
	return 0 == ps->size;
}
void StackPop(Stack* ps)
{
	if (StackEmpty(ps))
		return;
	ps->size--;
}
DataType StackTop(Stack* ps)
{
	assert(!StackEmpty(ps));
	return ps->array[ps->size - 1];

}
int StackSize(Stack* ps)
{
	assert(ps);
	return ps->size;
}
int main()
{
	Stack s;
	StackInit(&s);
	StackPush(&s, 1);
	StackPush(&s, 2);
	StackPush(&s, 3);
	StackPush(&s, 4);
	printf("%d\n", StackTop(&s));
	printf("%d\n", StackSize(&s));
	StackPop(&s);
	StackPop(&s);
	printf("%d\n", StackTop(&s));
	printf("%d\n", StackSize(&s));
	StackDestroy(&s);
	return 0;
}
可以看到,在用 C 语言实现时, Stack 相关操作函数有以下共性:
  •         每个函数的第一个参数都是Stack*
  •         函数中必须要对第一个参数检测,因为该参数可能会为NULL
  •         函数中都是通过Stack*参数操作栈的
  •         调用时必须传递Stack结构体变量的地址
        结构体中只能定义存放数据的结构,操作数据的方法不能放在结构体中,即数据和操作数据
的方式是分离开的,而且实现上相当复杂一点,涉及到大量指针操作,稍不注意可能就会出
错。

C++实现

typedef int DataType;
class Stack
{
public:
	void Init()
	{
		_array = (DataType*)malloc(sizeof(DataType) * 3);
		if (NULL == _array)
		{
			perror("malloc申请空间失败!!!");
			return;
		}
		_capacity = 3;
		_size = 0;
	}
	void Push(DataType data)
	{
		CheckCapacity();
		_array[_size] = data;
		_size++;
	}
	void Pop()
	{
		if (Empty())
			return;
		_size--;
	}
	DataType Top() { return _array[_size - 1]; }
	int Empty() { return 0 == _size; }
	int Size() { return _size; }
	void Destroy()
	{
		if (_array)
		{
			free(_array);
			_array = NULL;
			_capacity = 0;
			_size = 0;
		}
	}
private:
	void CheckCapacity()
	{
		if (_size == _capacity)
		{
			int newcapacity = _capacity * 2;
			DataType* temp = (DataType*)realloc(_array, newcapacity *
				sizeof(DataType));
			if (temp == NULL)
			{
				perror("realloc申请空间失败!!!");
				return;
			}
			_array = temp;
			_capacity = newcapacity;
		}
	}
private:
	DataType* _array;
	int _capacity;
	int _size;
};
int main()
{
	Stack s;
	s.Init();
	s.Push(1);
	s.Push(2);
	s.Push(3);
	s.Push(4);

	printf("%d\n", s.Top());
	printf("%d\n", s.Size());
	s.Pop();
	s.Pop();
	printf("%d\n", s.Top());
	printf("%d\n", s.Size());
	s.Destroy();
	return 0;
}

        

        C++中通过类可以将数据 以及 操作数据的方法进行完美结合,通过访问权限可以控制那些方法在 类外可以被调用,即封装 ,在使用时就像使用自己的成员一样,更符合人类对一件事物的认知。而且每个方法不需要传递Stack* 的参数了,编译器编译之后该参数会自动还原,即 C++ Stack * 参数是编译器维护的, C 语言中需用用户自己维护

猜你喜欢

转载自blog.csdn.net/m0_73367097/article/details/131011153