从C++开始的编程生活(4)——类的定义、访问限定符、类域、类的实例化和this指针

发布于:2025-07-22 ⋅ 阅读:(14) ⋅ 点赞:(0)

前言

本系列文章承接C语言的学习,需要有C语言的基础才能学会哦~
第3篇主要讲的是有关于C++的类的定义访问限定符类域类的实例化this指针
C++才起步,都很简单呢!

目录

前言

基本语法

访问限定符

基本语法

类域

类的实例化 

内存对齐规则

this指针

封装(初步了解)


class为类的关键字,后跟类名,{ }中为类的主体。主体中内容称为类的成员类中的变量称为类的属性或者成员变量类中的函数称为方法或者成员函数

基本语法

为了区分方法的形参和类中的成员变量,通常会在变量前后加一个下划线,具体怎么标识,看公司或者团队要求。

//类与对象
class Stack
{
	//方法
	void Init(int capacity = 4)
	{
		_array = (int*)malloc(sizeof(int) * capacity);
		if (nullptr == _array)
		{
			perror("malloc申请空间失败!\n");
			return;
		}
		_capacity = capacity;
		_top = 0;
	}
	void Push(int x)
	{
		//扩容步骤(省略)
		_array[_top++] = x;
	}
	//·······(省略栈的各种函数)


	//成员变量
	int* _array;
	size_t _capacity;
	size_t _top;
};
//类名就是类型

类中的成员函数,默认为inline函数

访问限定符

public公有,在类外可以直接被访问。设计时成员函数一般是公有的。
private私有,在类外不能直接被访问。设计时成员变量一般是私有的。
protect保护,在类外不能直接被访问。在继承上,和private有区别(在继承详细说明)。

基本语法

class Stack
{
//公有
public:
	void Init(int capacity = 4)
	{
		_array = (int*)malloc(sizeof(int) * capacity);
		if (nullptr == _array)
		{
			perror("malloc申请空间失败!\n");
			return;
		}
		_capacity = capacity;
		_top = 0;
	}
//私有
private:
	int* _array;
	size_t _capacity;
	size_t _top;
};

如上,跟在不同的访问限定符后,受不同的访问限定。

 
C++兼容C语言的struct,同时又升级了struct。
C++中,struct和类的唯一区别在于:struct的成员变量和方法默认为publicclass默认为private为求严谨,最好自己指明访问限定符

//不加访问限定符,默认为public
struct Person
{
	void Init(const char name[5])
	{
		strcpy(_name,name);
	}
	void Print()
	{
		cout << "姓名:" << _name << endl;
	}

	char _name[5];
};


int main()
{
	//可在外部直接使用
    Person p1;
	p1.Init("张三");
	p1.Print();
	return 0;
}

类域

由类定义的一个新的作用域,类的所有成员都在类域中。类域使得不同的类可以有同名的成员。和命名空间类似,它影响的是编译器的查找顺序规则(具体去看我博客内的C++第一篇喔~)。

成员函数可以进行声明和定义的分离。
一般我们将声明放在类中,定义放在另一个文件中。并且为了标识该方法所属的类,需要用到域作用限定符  :: 

void Stack::Init(int capacity)//注意定义处不要写缺省参数,缺省参数写在声明
{
    //函数实现省略···
}

类的实例化 

类中的成员变量在没有实例化时,均不开辟空间,只是一个声明。我们要将类实例化成对象后,它才能够存储数据,我们才能对具体的对象进行操作

class Date
{
public:
	void Init(int year, int month, int day)
	{
		_year = year;
		_month = month;
		_day = day;
	}
	void Print()
	{
		cout << _year << "/" << _month << "/" << _day << endl;
	}
private:
	int _year;
	int _month;
	int _day;
};

int main()
{
	Date d1;//实例化出对象d1
	Date d2;//实例化出对象d2
	d1.Init(2025, 7, 20);
	d2.Init(2025, 7, 25);

	d1.Print();
	d2.Print();

	cout << sizeof(d1) << endl;//输出12,成员变量共12个字节
	cout << sizeof(d2) << endl;//输出12,成员变量共12个字节
	return 0;
}

实例化后,对象只存储成员变量,不存储方法指针。因为同一类的对象使用的是相同的方法,所以将方法存储在公共代码区即可,不存储在实例对象里。否则,会重复存储,浪费空间。

内存对齐规则

成员变量存储,遵循C语言的内存对齐规则。

第一个成员变量在类起始地址偏移量为0处。
②其他成员变量要对齐到对齐数的整数倍地址处
对齐数 = 编译器默认对齐数 与 该成员大小 的较小值
④VS编译器默认的对齐数是8
⑤类的总大小为默认对齐数的整数倍
⑥类中没有成员时(如仿函数类),总大小为1byte。即使没有也要开辟空间占位,以表示存在实例对象。

内存对齐的目的方便读取,读取数据时可以从在数据类型大小的整数倍位置读取,不用一字节一字节读,而是跳跃读取找到位置后可以一次性读取,不用再一个字节一个字节拼起来。

this指针

用于指明类方法中区分访问的成员方法。类方法存储在公共代码区,在类方法的角度来看,调用它时,该方法并不清楚是哪个对象调用的它。这就要用到this指针。

类方法中实际上还会隐含一个参数,

void Init(int year, int month, int day)
{
    //略···
}

//在形参列表首位,存在一个省略的参数this指针
void Init(Date* const this, int year, int month, int day)
{
    //略···
}

我们可以看到有const修饰,该隐藏参数是不可以修改的
调用时,会传入调用方法的对象的地址作为this指针

d1.Init(2025, 7, 21);
//d1.Init(&d1, 2025, 7,21);
//实际上是这样传参的,但是不能这样写

 C++编译器会自动添加的隐含的this,程序员不可以自行添加,会报错。但是可以在函数体内添加使用

void Print()
{
	cout << _year << "/" << _month << "/" << _day << endl;
}
//等价于
void Print()
{
	cout << this->_year << "/" << this->_month << "/" << this->_day << endl;
}

通过this指针,对象调用类方法时,才可以在类方法内访问对象的属性。

类指针的易错点:

class A
{
public:
	void Print()
	{
		cout << "Hi!" << endl;
	}
private:
	int _a;
};

class B
{
public:
	void Print()
	{
		cout << "Hi!" << endl;
		cout << _b << endl;
	}
private:
	int _b;
};

int main()
{
    //正常运行,输出“Hi!”
	A* pa = nullptr;
	pa->Print();
    //运行崩溃
	B* pb = nullptr;
	pb->Print();
	
    return;
}

如上,papb都是空指针
pa指针调用Print方法能正常运行,是因为运行时未对这个空指针进行解引用操作
pb指针调用Print方法会运行崩溃,是因为运行到语句 cout << _b << endl 时,_b前有隐藏的this指针,所以这里实际上有一个 this->_b ,这里的this即是传入的pb空指针,发生解引用错误
(“ 指针-> ”为解引用操作喔~)

ps:this指针的创建在栈区

封装(初步了解)

目的:C++将数据和函数放在类中,隐藏细节和复杂部分,只需要确保代码能实现目的即可。靠访问限定符,约束和管理程序员访问数据,避免细节上的错误

关于封装更多的知识,在之后还有更多可以学习的,敬请关注!!

❤~~本文完结!!感谢观看!!欢迎来我博客做客~~❤

网站公告

今日签到

点亮在社区的每一天
去签到