C++:类与对象(一)

本文介绍C++中类与对象的核心概念。首先讲解类的定义格式、访问限定符(public、private、protected)以及类域的作用;随后介绍对象的实例化过程、对象大小的计算规则,并解释空类为何占用一个字节;最后说明this指针的隐藏机制及其在成员函数调用中的作用。

类

类的定义格式

C++中的类可以简单理解为将一个功能整体打包封装,而这个打包好的东西就称之为"类"。

类中包含变量和函数,它们分别被称之为"成员变量","成员函数"(类的方法)。

类的定义通过class 这个关键字,后面接上类的名字,比如Stack,在加上括号和分号。

cpp 复制代码
#define _CRT_SECURE_NO_WARNINGS 1
#include <iostream>
#include <assert.h>
using namespace std;

class Stack
{
public:
	//成员函数
	void Init(int n = 4)
	{
		_array = (int*)malloc(sizeof(int) * n);
		if (_array == NULL)
		{
			perror("malloc");
			return;
		}
		_capacity = n;
		_top = 0;
	}

	void Push(int x)
	{
		//扩容
		if (_top == _capacity)
		{
			int* tmp = (int*)realloc(_array, sizeof(int) * _capacity * 2);
			if (tmp == NULL)
			{
				perror("realloc");
				return;
			}
			_capacity *= 2;
			_array = tmp;
		}
		_array[_top++] = x;
	}

	int Top()
	{
		assert(_top > 0);
		return _array[_top - 1];
	}

	void Destroy()
	{
		free(_array);
		_array = nullptr;
		_top = _capacity = 0;
	}


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

访问限定符

我们还可以注意到public和private这两个关键字。

它们被称为"访问限定符"。

public修饰的成员能在类外访问,而private和protected则不能在类外访问。后两者的区别会放在后续谈。

需要注意的是,如果class定义的成员没有被访问限定符修饰,那么就会默认为private,而struct则是public。

一个习惯是,成员变量通常为private,而成员函数为public。

类域

类指定了一个新的作用域。如果你把函数声明放在类中,定义放在类外,那么定义使用域操作符**"::"**指定该定义到底属于那个类。

cpp 复制代码
#define _CRT_SECURE_NO_WARNINGS 1
#include <iostream>
#include <assert.h>
using namespace std;

class Stack
{
public:
	//成员函数
	void Init(int n = 4)
	{
		_array = (int*)malloc(sizeof(int) * n);
		if (_array == NULL)
		{
			perror("malloc");
			return;
		}
		_capacity = n;
		_top = 0;
	}

	void Push(int x);

	int Top()
	{
		assert(_top > 0);
		return _array[_top - 1];
	}

	void Destroy()
	{
		free(_array);
		_array = nullptr;
		_top = _capacity = 0;
	}


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

void Stack::Push(int x)
{
	//扩容
	if (_top == _capacity)
	{
		int* tmp = (int*)realloc(_array, sizeof(int) * _capacity * 2);
		if (tmp == NULL)
		{
			perror("realloc");
			return;
		}
		_capacity *= 2;
		_array = tmp;
	}
	_array[_top++] = x;
}

在此例中,如果不用域操作符,Push函数就会被当作全局函数处理。

对象

类的实例化

现实中,房屋都有设计图,但图中的事物是没有实体的设计,而当你按照图纸把它造出来时,它才拥有实体。

类比到这里,类就像设计图,它没有实体,也就是没有被分配内存,只有实例化------创建了对象后,那个对象才算是实体,才是被分配了内存。

cpp 复制代码
int main()
{
	Stack st1;//实例化

	st1.Init();
	st1.Push(1);
	st1.Push(2);
	st1.Push(3);
	st1.Push(4);
	st1.Push(5);
	cout << st1.Top() << endl;
	st1.Destroy();
	return 0;
}

这里顺带说一下,实例化出的对象包含每个成员变量,但不包含函数,也没有存储它们的指针。

毕竟函数总是一样的,如果每个对象都包含函数,会非常浪费空间。再一个,指针本质上是地址,编译器会在编译链接时,找到函数地址,将调用函数编译为汇编指令,而不是在运行时找。

对象的大小

对象既然有实体,那就必然有大小。它的大小计算方式和结构体类似,具体如下:

1.第一个成员对齐在偏移量为零处。

2.其它成员对齐到对齐数的整数倍的地址处。(对齐数为默认对齐数和该成员大小的较小值,VS默认对齐数是8)

3.总大小为最大对齐数的整数倍

4.如果嵌套了结构体,那么嵌套的结构体对齐到自身最大对齐数的地址处,整个结构体的大小为包含了嵌套结构体成员的最大对齐数的整数倍。

我们来看下面例子:

cpp 复制代码
#include <iostream>
#include <assert.h>
using namespace std;

class A
{
public:
	void Print()
	{
		cout << _ch << endl;
	}
private:
	char _ch;
	int _i;
};

class B
{
public:
	void Print()
	{

	}

};

class C
{

};

int main()
{
	A a;
	B b;
	C c;
	cout << sizeof(a) << endl;
	cout << sizeof(b) << endl;
	cout << sizeof(c) << endl;
	return 0;
}

最终算出结果为:8 1 1

我们发现,在类中,即使没有成员变量,大小仍然会有一个字节。毕竟如果一个字节都不给,怎么证明这个对象存在过?这里给一个字节是为了保证不同对象有不同的地址。

this指针

在刚刚的stack类的例子中,如果我们实例化出两个对象st1,st2,那么它们所包含的函数都是相同的,可问题在于,函数体中似乎没有区分对象的功能,那在调用时,它究竟是如何决定,我是该拿st1的数据,还是st2的数据的呢?

其实每个成员函数的第一个形参隐藏了一个this指针参数,用它来访问对应对象的成员变量,字面意思上的告诉函数是"这个"对象。

比如stack的Init的真面目时是:

cpp 复制代码
void Init(Stack* const this, int n = 4)
{
	this->_array = (int*)malloc(sizeof(int) * n);
	if (this->_array == NULL)
	{
		perror("malloc");
		return;
	}
	this->_capacity = n;
	this->_top = 0;
}

注意,C++规定不能再实参和形参位置上显示地写this指针,但是我们可以在函数体内部显示使用this指针。

相关推荐
死磕音视频2 小时前
让小模型做选择题:限定候选项并读取 logits 概率的入门实践(附 Python 代码)
开发语言·python·大模型·文本分类·transformers
WL学习笔记4 小时前
C & C++ 内存管理
c++·c++内存管理
顽疲5 小时前
Java vue 养老系统源码详解:月账单 care_month_bill 与 Quartz 扣费 Job 实践
java·开发语言·vue.js·vue养老·springboot养老·java养老
Wang's Blog5 小时前
Java 项目实战: 交友项目 - 安装开发工具与环境准备
java·开发语言·交友
启观川6 小时前
数据结构与算法-第 3 章 常用算法-贪心算法
数据结构·笔记·python·算法·贪心算法
思陌Ai算法定制6 小时前
医疗AI系统架构的安全护栏:一句提示让大模型有害医疗决策从16.6%降到10.1%
经验分享
m0_587383006 小时前
无人自助拼豆系统核心功能开发与部署落地全流程实战指南
java·经验分享·后端·struts·架构
宛 禾7 小时前
Qt 控件入门:QLabel 从拖拽到对象树,一篇讲透
c++·qt·学习
hetao17338377 小时前
联盟场-提高组-R7 & ZYZSC-S-Round 11
c++·算法
程序喵大人7 小时前
【C++入门】编译链接模型 - 07 链接器怎样把符号对上号
开发语言·c++·编译器·编译链接·链接器