C++:类和对象 I(访问限定符、this指针)

目录

类的定义

类的大小

访问限定符

实例化

this指针



 

类的定义

class就是类,class是C++中的一个关键字

当然类也可以是C语言中的struct,C++兼容struct,甚至还有一些升级

定义类的方式

class Date
{

};

和C语言的struct一样,class是C++中定义类的一个关键字,Date是这个类的名字,我们需要在后面跟上一个 {}和;,{}里面可以放变量,函数等

定义在类里面的成员函数默认为inline

类的大小

class和struct的大小计算方式一致,和在C语言时的计算方法一致,以下博客有结构体的大小计算讲解

C语言:自定义类型:结构体-CSDN博客

明明C++的类和C语言不同,C语言只能放变量,C++不仅能放变量还能放函数,为什么还是按照C语言的方式只计算成员变量的方法来计算结构体的大小呢?

这是因为成员函数实际上并不存储在类的实例的内存空间中,它们存储在代码段内,而类的实例只存储成员变量

为什么存储在代码段?

因为在类外我们是需要定义多个该类的变量的,例如日期类:

#include<iostream>
using namespace std;

class Date
{
public:
	// ...
private:
	int _year;
	int _month;
	int _day;
};

int main()
{
	Date d1;
	Date d2;
	Date d3;
	// ...
	return 0;
}

每个日期类对象d1、d2、d3毋庸置疑一定要有它们专属的变量(_year、_month、_day),这才能让它们三个都有各自的日期

那为什么不要每一个日期类对象都有一个成员函数?因为浪费

我们只需要一个函数足以,这个函数就存储在代码段中,当它们需要这个函数时就去代码段中调用这个函数,将它们专有的成员变量传过去即可,那么怎么传呢?具体看下面this指针的讲解

访问限定符

这是跟C语言不同的地方,C语言没有访问限定符的概念,比较自由

是C++一种实现封装的方式,通过访问限定符选择性的将接口给外部的用户使用

有三种访问限定符:public、private、protected

具体使用方法如下: 

class Date
{
public:
	void Print()
	{
		cout << _year << "/" << _month << "/" << _day << endl;
	}

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

public的意思是公有的,公有的就代表可以被外部所访问,例如在main函数中可以使用

private的意思是私有的,私有的就代表不可以被外部所访问,一般都设置成员变量为私有的

protected是受保护的,它发挥作用的地方在继承的那部分,其他和private一致,不能被外部所访问

在继承中,protected外部不能访问,但是它的派生类(子类)可以访问到protected的内容,而private依旧不能访问

 class定义成员没有被访问限定符修饰时默认为private,struct则默认为public,这也是他们在C++中的区别

我们要怎么访问类里面呢?

class Date
{
public:
	void Print();

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

void Date::Print()
{
	cout << _year << "/" << _month << "/" << _day << endl;
}

int main()
{
	Date d1;
	d1.Print();
	return 0;
}

这是在类里面声明了Print()函数,在类外面定义了Print()函数

要注意的就是我们需要用::访问限定符访问Date里面,这样才能知道函数内部的_year、_month、_day是谁

访问函数只需要用 . 即可

实例化

class Date
{
public:
	void Print();
    // ...

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

int main()
{
	Date d1;
	d1.Print();
	return 0;
}

在这个日期类中,private里的成员函数都只是声明,并不是定义,并没有开空间,所以他们不是实例化,他们就像一张图纸,只可以看不可以做

而下面的d1就是实例化出了一个日期类对象,可以使用它里面的成员函数

this指针

#include<iostream>
using namespace std;

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;
    Date d2;

	d1.Init(2024, 7, 12);
	d1.Print();

	return 0;
}

在上面的代码中,有了Date类的初始化函数Init,和打印函数Print,这样我们就可以给一个Date对象初始化和打印了

运行结果:

前面有说既然类里面的函数只存在代码区只需要一份共同调用即可,那我们使用d1对象调用的时候函数里面怎么拿到d1的成员变量?为什么不是d2?

这里其实C++隐含了一个this指针,是利用了this指针解决了这个问题

我们的函数其实可以写成这样

class Date
{
public:
	void Init(int year, int month, int day)
	{
		this->_year = year;
		this->_month = month;
		this->_day = day;
	}

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

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

照样可以运行成功,结果一样

其实函数主题和调用相当于这样

void Init(Date* const this, int year, int month, int day)
{
	this->_year = year;
	this->_month = month;
	this->_day = day;
}

void Print(Date* const this)
{
	cout << this->_year << "/" << this->_month << "/" << this->_day << endl;
}

int main()
{
	Date d1;
	d1.Init(&d1, 2024, 7, 12);
	d1.Print(&d1);

	return 0;
}

但实际上我们是不能这样自己显式的把this写在函数参数上的,编译器会报错

这些都是编译器帮我们做的是,编译器自动的把d1的地址传过去,自动用this指针访问了,所以我们不需要写

但是函数内部我们是可以使用这个this指针的,因为后续我们需要这个this指针,并不只是上面单纯的初始化、打印之类的


最近更新

  1. docker php8.1+nginx base 镜像 dockerfile 配置

    2024-07-13 18:32:02       67 阅读
  2. Could not load dynamic library ‘cudart64_100.dll‘

    2024-07-13 18:32:02       72 阅读
  3. 在Django里面运行非项目文件

    2024-07-13 18:32:02       58 阅读
  4. Python语言-面向对象

    2024-07-13 18:32:02       69 阅读

热门阅读

  1. jmeter文件下载接口处理

    2024-07-13 18:32:02       21 阅读
  2. python库 - modelscope

    2024-07-13 18:32:02       20 阅读
  3. C语言 求方程 ax^2 + bx + c = 0 的根

    2024-07-13 18:32:02       19 阅读
  4. 第一节 SHELL脚本中的常用命令(6)

    2024-07-13 18:32:02       19 阅读
  5. bert训练的一些技巧(rand() < self.skipgram_prb)

    2024-07-13 18:32:02       18 阅读
  6. Dubbo 负载均衡(Load Balance)

    2024-07-13 18:32:02       19 阅读
  7. 编译的艺术:在Gradle中精调编译器选项

    2024-07-13 18:32:02       22 阅读
  8. 如何防御sql注入攻击

    2024-07-13 18:32:02       20 阅读
  9. html基础篇

    2024-07-13 18:32:02       20 阅读
  10. SpringBoot的启动流程?

    2024-07-13 18:32:02       20 阅读