c++的类与对象(上)

18 篇文章 0 订阅

c++中相对于c语言最大的创新就是类的出现,那么类究竟是怎么一回事呢?

今天好好了解一下吧;

目录

什么是面向对象

 类的定义

类的关键字(访问限定符)

类的作用域

类和命名空间的不同

 类的内存计算

this指针


什么是面向对象

我们都知道,c++是面向对象的语言,而c语言是面向过程的语言;

那么什么是面向对象;

什么是面向过程呢?

面向对象的语言

 所谓面向对象的语言就是将一个系统中需要用到的东西,全部抽象为一个个对象;

然后靠对象的交互完成系统;

是一种 “自下而上” 的编程语言,也就是先设计好底层组件,然后组装起来;

而面向对象的这种形式就造就了面向对象语言的特点:

封装性,多态性,继承性;

面向过程的语言

而面向过程则是先定好一个系统的框架,然后再在里面添砖加瓦;

也就是在源文件内部添加好一个个函数(方法);

这里的不同,导致两种类型语言使用场景不同;

c++中最重要的莫过于类这一改进,也是导致c++是面向对象的最重要的原因;

因此想要学好c++,学好类是必不可少的;

事不宜迟,我们就来学习类吧~ 

 类的定义

class (classname)

{

       // 变量成员或者方法;

}; 

 类的定义需要有 class 关键字,定义好名字后再在里面定义成员或者方法;

结构体和类的定义很类似,但是类却可以定义方法

而类定义方法就是c++对于结构体最大的改进;

那么我们就实际上感受类的作用吧;

#include<iostream>

using namespace std;

class Date {
private :
	int _year;
	int _month;
	int  _day;
public:
	void Init(int year = 2022, int month = 10, int day = 4)
	{
		_year = year;
		_month = month;
		_day = day;
	}

	void Read()
	{
		cout << "year = " << _year << endl;
		cout << "month = " << _month << endl;
		cout << "day = " << _day << endl;
	}
};

int main()
{
	Date a;
	a.Init();
	a.Read();
	return 0;
}

当然,类和结构体一样,能够将函数的声明与定义放在不同的位置;

若是将类的函数声明和定义放在一起,那么这个函数相当于内联函数;

//Date.h中

#include<iostream>
class Date {
private:
	int _year;
	int _month;
	int _day;
public:
	void Read();
	void Init(int year = 2022,int month = 10,int day = 4);
};

//Date.cpp


#include"Date.h"

using namespace std;

void Date::Init(int year = 2022, int month = 10, int day = 4)
{
	_year = year;
	_month = month;
	_day = day;
}

void Date::Read()
{
	cout << "year = " << _year << endl;
	cout << "month = " << _month << endl;
	cout << "day = " << _day << endl;
}

 我们可以看到,这个类中不仅有成员变量,还有各种方法;

还有这种没有了解过的关键字:private,pubulic;

接下来我们就慢慢了解吧;

(顺带一提,类的成员变量在哪里都能用,只要是在类的内部就行了)

类的关键字(访问限定符)

之前的类里面出现了两种访问限定符;

而类一共有以下三种访问限定符;

private(私有)

public(公有)

protect(保护)

那么访问限定符究竟有什么用呢?

又有什么区别呢?我们来看看;

访问限定符的作用:

1. public 修饰的变量或者方法可以在类外直接访问;

2. private 和 public 修饰的变量或者方法只能在类内部访问;

3. 访问限定符的作用域一直持续到下一个访问限定符

4. 若是后面没有别的访问限定符,则作用域在 } 处结束;

5. class 中默认的权限是 private;//struct 也有默认权限,不过是public

看完访问限定符的作用和 class 的默认权限后,我们可以知道访问限定符有多重要了;

不过为什么需要创建这三个访问限定符呢?

这不是导致使用类的时候还需要注意这个限定符吗?

实际上这就涉及到面向对象的语言的封装性的特点了;

我们用好了访问限定符,就能选择哪些接口能够供给用户使用,哪些需要隐藏;

这就能够更方便用户的使用,也能隐藏好内部的细节;

类的作用域

之前将类的定义和声明分离的时候,就已经演示过在类的外面定义类的成员了;

这里类的作用域实际上就和普通定义结构体一样,只是需要用 :: 来声明罢了;

这一点和命名空间很类似,但是类和命名空间还是有不同的;

那么类和命名空间有什么不同呢?

类和命名空间的不同

我们首先需要明白一点,命名空间内部的变量都是可以直接用的;

但是类内部的变量却不行;

这就涉及到类的实例化了;

类的实例化:用类类型创建一个对象,就是类的实例化;

当类没有定义一个对象的时候,类就并没有占用实际的空间;

类内部变量也没有占用实际空间,这点和结构体类似;

而只有用类创建了一个对象,该对象才会在内存空间内开辟一个空间

不过一个类对象在内存空间实际上会占多少内存呢?这又是一个需要探讨的点;

 类的内存计算

之前说过,类是结构体的改进,那么类的内存计算和结构体的内存计算应该类似;

但是,类和结构体不一样的是,类内部可以定义方法的,那么类内部的方法会不会影响类的大小?

class Date {
private:
	int year;
	int month;
	int day;
public:
	void Init(int _year = 2022, int _month = 10, int _day = 5)
	{
		//.......
	}

	void Read()
	{
		//....
	}
};

我们敲上这样一段代码,按照结构体的方法,我们先忽略 Init 和 Read 两个函数;

那么单纯计算三个变量,那么该类应该是12个字节的大小;

那么两个函数该怎么办呢?是将两个函数看作函数指针,还是怎么做?

我们直接看结果:

 我们能够看到,实际上这个类的大小就是12个字节;

那么这两个函数怎么办呢?难不成这两个函数实际上是没有占空间的吗?

实际上,c++的创始人想到了一个绝佳的方法;

将类里面的方法都放在一块内存区域中,只给成员变量开辟不同的区域;

此外,类的内存大小计算内存对齐之类的,全部和结构体是一样的

不过有一个例外,那就是空类; 

 我们将类的成员全部屏蔽掉,可以看到即使是空类,也会有一个字节的空间;

用来标识这是空类;

明白了类的方法如何计算之后,我们再来看看结构体内存对齐规则;

这个规则可以直接用于类的内存计算;

结构体的内存对齐规则:

1. 第一个成员在与结构体偏移量为 0 的地址处。
2. 其他成员变量要对齐到某个数字(对齐数)的整数倍的地址处。
注意:对齐数 = 编译器默认的一个对齐数 与 该成员大小的较小值
VS 中默认的对齐数为 8
3. 结构体总大小为:最大对齐数(所有变量类型最大者与默认对齐参数取最小)的整数倍。
4. 如果嵌套了结构体的情况,嵌套的结构体对齐到自己的最大对齐数的整数倍处,结构体的整
体大小就是所有最大对齐数(含嵌套结构体的对齐数)的整数倍。

拿刚刚的类来说明:就是这样

 从偏移量为0开始,按照规则开始计算,可以得出最终字节大小为12;

在了解类的内存计算后,又来了一个新的问题;

既然类的方法都是在同一个空间内部,那么编译器怎么知道方法中的变量,是哪个对象的变量呢?

这就是this指针出场时候了;

this指针

我们先来看看用类类型创建两个对象,用方法初始化,能不能成功;

class Date {
private:
	int _year;
	int _month;
	int _day;
public:
	void Init(int year = 2022, int month = 10, int day = 5)
	{
		_year = year;
		_month = month;
		_day = day;
	}

	void Read()
	{
		cout << "year = " << _year << endl;
		cout << "month = " << _month << endl;
		cout << "day = " << _day << endl;
	}
};

int main()
{
	Date d1, d2;
	d1.Init(2022, 10, 6);
	d2.Init(2023, 10, 6);
	d1.Read();
	d2.Read();
	return 0;
}

 可以看到确实成功了;

这就是this指针的用处了;

同学们这个时候就会很疑惑;

明明方法内部没有this指针啊?

为什么能够辨别不同的对象?

实际上this是一个隐藏的指针,会指向当前对象;

函数内部所有成员变量的操作都是通过this指针进行的;

只是this指针是隐藏的,用户可以不用理会,当然,我们也可以加上this指针;

 

 就像这样,也是可以的;

而由于平时我们的this都是隐藏的;

那么我们像使用 Init 这类成员变量和形参相同的函数时;

最好给成员变量前面加上" _ " 这种特殊符号,用以区别,否则编译器可能会混乱;

 不过知道了编译器如何区别不同的对象之后,还有一个问题;

那就是this指针究竟是存在哪里的?

而this指针的特性是什么呢?

这里直接介绍一下;

this指针的特性

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

就像上面的Date类,this指针的类型是 Date * const; 

总结

类作为c++最大的一个改进,其地位在c++中是十分高的;

而这里只是介绍了类的定义,内存计算以及this指针这几个部分的知识;

而类的内容远远不止如此;

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值