💓博主CSDN主页:杭电码农-NEO💓
⏩专栏分类:C++初阶之路⏪
🚚代码仓库:NEO的学习日记🚚
🌹关注我🫵带你学习C++
🔝🔝

类和对象-上
- 1. 前言
 - 2. 类的引入
 - 3. 类的定义
 - 4. 类的访问限定符
 - 5. 类的实例化
 - 6. 类对象模型
 - 6.1 类对象的存储模式
 
- 7. this指针
 - 7.1 this指针的特性
 - 7.2 this指针的用处
 
- 8. 总结以及拓展
 
1. 前言
C语言是面向过程的语言
 关注的是过程
 而C++是面向对象的语言
 关注的是对象
而类和对象就是面向对象的基础!

C++为了兼容C语言
 保留了原先的玩法,并且增加了新的玩法
本章重点:
本篇文章着重讲解类的概念,基本特性
成员函数的性质,和最重要的this指针
2. 类的引入
C语言的结构体功能单一
 只能定义成员变量,不能定义函数
 而C++中新增了一个玩法:
 可以定义成员函数
比如:
struct NEO
{
	int a;
	char b[20];
	void test()//成员函数
	{
		cout<<"杭州电子科技大学"<< endl;
	}
	void push(char ch,int i)//成员函数
	{
		b[i] = ch;
	}
};
int main()
{
	NEO tmp;
	tmp.test();//会打印"杭州电子科技大学"
	tmp.push('a',1);//数组b下标为1的位置会被插入一个字符'a'
}
 
在C++中,C的结构体就是类
 并且C++中更喜欢用class替代struct
3. 类的定义
class className
{
	// 类体:由成员函数和成员变量组成
};   一定要注意后面的分号
 
类的定义与结构体类似
 只不过将struct换成了class
类成员函数的两种定义方式:
声明和定义都放在类中:
class people
{
	char* name;
	char* sex;
	int height;
	int age;
	void peoinfo()//打印此人的消息
	{
		cout<<name<<" "<<sex<<" "<<height<<" "<<age;
	}
};
 
这个类的成员函数的声明和定义都在类中
编译器就可能把此函数当作内联处理!
只要是在类中定义的函数都会被看作内联
当然这只是给编译器一建议
 具体会不会内当作内联要看代码长度
类函数声明定义分开
一般说的声明和定义分开是指:
 声明放在.h文件,定义放在.cpp文件
.h文件
class people
{
	char* name;
	char* sex;
	int height;
	int age;
	void peoinfo()//打印此人的消息
};
 
.cpp文件(错误实例)
void peoinfo()//打印此人的消息
	{
		cout<<name<<" "<<sex<<" "<<height<<" "<<age;
	}
 
注意:在另一个文件中,必须要加上类名::
 否则系统不知道你是要新定义一个函数
 还是要定义已经声明过的函数
正解:
void people::peoinfo()//打印此人的消息
	{
		cout<<name<<" "<<sex<<" "<<height<<" "<<age;
	}
 
4. 类的访问限定符
首先介绍三个访问限定符:

访问限定符说明:
-  
public修饰的成员在类外
可以直接被访问 -  
protected和private修饰的成员
在类外不能直接被访问 -  
访问权限作用域:
从该访问限定符出现的位置开始直到
下一个访问限定符出现时为止 -  
如果后面没有访问限定符了
作用域就一直到类结束 -  
class的默认访问权限为private
struct为public(因为要兼容C) 
举例说明:
class NEO
{
public:
	void test1()
	{
		cout<<"haha";
	}
	void test2()
	{
		cout<<"hehe";
	}
private:
	int a;
	char b[20];
	double c;
}
int main()
{
	NEO tmp;
	tmp.test1();//正常运行
	tmp.a = 10;//运行报错
	tmp.c = 20;//运行报错
	return 0;
}
 
此类中,public和private
之间的成员是共有的,类外可以访问
private到类结束的成员是私有的
类外不能访问!
需要注意的点:
不管成员函数是共有还是私有
 也不管成员变量是共有还是私有
 成员函数都可以访问到成员变量!
5. 类的实例化
用类类型创建对象的过程,称为类的实例化
在实例化类对象之前,这个类并不占用内存
比如:
class Person
{
public:
	void printper()
	{
		cout<<name;
	}
private:
	char* name;
};
int main()
{
	Person.name = "NEO";//编译报错,还没有实例化对象
	Person p1;
	return 0;
}
 
若没有实例化对象p1
 这个class类是不会开辟空间的!
class类就像一个设计图纸一样
在按照这个图纸建设房子前
这块区域是没有空间占用的
实例化对象就像按照图纸修房子一样
会占用空间

6. 类对象模型
怎么计算一个class类的大小?
例如:下面这两个类:
class A
{
	void PrintA()
	{
		cout << a << endl;
	}
	int a;
	char b;
};
class B
{
	int a;
	char b;
};
int main()
{
	printf("类A的大小: %d\n", sizeof(A));
	printf("类B的大小: %d\n", sizeof(B));
	return 0;
}
 

结论:
- 类中的成员函数不算在类的大小中
 - 类的大小遵守结构体内存对齐规则
 - 空类(没有成员变量)的大小是1字节
 
注:如果你不知道结构体内存对齐规则
 请点击:结构体内存对齐规则
6.1 类对象的存储模式
为啥类中的成员函数不占空间?
 那函数存储在什么位置?
带着这样的疑惑来看看类的存储模式:
- 类成员变量存储在实例化对象中
 - 类成员函数存储在公共的代码段
 
可以用下面这张图来理解:

对类成员变量的解释:
由于每一个对象中的变量的值可能不同
所以成员变量存储在不同的对象中
对类成员函数的解释:
但是每个对象调用的函数是相同的
为了节省空间,将成员函数从对象中剥离
到公共代码段,不管实例化多少个对象
只要调用成员函数就会去代码段找!
7. this指针
先看以下的日期类:
class Date
{ 
public:
	void Init(int year, int month, int day)
	{
 		_year = year;
	 	_month = month;
	    _day = day;
    }
private:
 	int _year;     // 年
	int _month;    // 月
	int _day;      // 日
};
int main()
{
	Date d1;
	d1.Init(2023,7,22);//初始化对象
	return 0;
}
 
看似Init只有三个参数
 看似调用Init时只传了三个参数
但其实还有一个隐藏的指针this!
可以用下图理解this的位置:

并且在每一个成员变量之前
 都有this指针解引用访问它:

7.1 this指针的特性
基本特性:
-  
this指针的类型:const 类类型 *
即成员函数中,不能给this指针赋值 -  
只能在“成员函数”的内部使用
 -  
this指针不能我们显示去写
也不能我们显示去传对象地址 -  
this指针存储在栈区,不存储在对象中
 
对特性的理解:
不能这样写代码:
class A
{ 
void Init(A* this,int a)
{
	_a=a;
}
 int _a;
};
int main()
{
	A a1;
	a1(&a,10);
}
 
假如这样写代码,那么函数参数就有三个
系统还是会自动传this指针,会报错
7.2 this指针的用处
假设我们实例化了两个对象
 分别是d1和d2
class Date
{ 
public:
	void Init(int year, int month, int day)
	{
 		_year = year;
	 	_month = month;
	    _day = day;
    }
private:
 	int _year;     // 年
	int _month;    // 月
	int _day;      // 日
};
int main()
{
	Date d1;
	Date d2;
	d1.Init(2023,7,22);//初始化对象
	d2.Init(2023,7,23);
	return 0;
}
 
已知成员函数是放在公共代码段的
 假如没有this指针存在
 函数体又没有区别不同对象的手段
那么就会出现一个问题:
 对象d1调用函数Init时,函数不知道是
 哪一个对象调用了它,就无法区分对象
使用this指针将对象的地址传入函数中
函数体就可以区分不同对象了!
8. 总结以及拓展
本章是类和对象的入门篇
 只介绍了类的解基本概念和特性
 其中比较重要的是this指针
 它还会陪伴我们很久!
基础不牢,地动山摇
 类学不会,学C++就受罪

拓展: C++命名方式
C++又很多习惯的命名方式
 这里介绍一个:驼峰法命名
- 单词和单纯之间首字母大写
 - 函数名,类名首字母大写
 - 变量首字母小写,后面单词首字母大写
 - 成员变量的首字母前加下划线_
 
举例说明:
class Date
{ 
public:
  void InitDate(int year, int month, int day)//initialize date
  {                                          //初始化日期,简写后,I和D要大写
    _year = year;
    _month = month;
    _day = day;
  }
  void PrintInfo()//printf information,简写后P和I要大写
  {
    cout <<_year<< "-" <<_month << "-"<< _day <<endl;
  }
private:
  int _year; //成员变量前面加_
  int _month;
  int _day;     
};
 



















