欢迎来到海盗猫鸥的博客~~
本篇我们将学习部分C++中的类和对象相关知识沃~
(´• ω •`)ノ算我一个~
目录
类的定义
类的定义及使用
访问限定符
类域
实例化
实例化概念:
对象大小:
内存对齐规则:
注意点:
this指针
结语
类的定义
类的定义及使用
-
class为类的关键字,后接类的名字,同命名空间一样使用{}来限定主体内容,且限定的范围也是一个域,但不同于命名空间,类的最后要加上分号结尾;
class hdmo {//声明成员变量(属性)、函数(方法)等//...//... };
-
类中的内容为类的成员:类中的变量称为类的属性或者成员变量;类中的函数称为类的方法或者成员函数。
-
类中的函数默认为inline内联函数,可以将函~数的定义和声明分开,使其成为普通函数,但需要在函数定义的地方加上函数所属的类域:
class hdmo { public://访问限定符int y = 10;void Fun(int x = 10); }; void hdmo::Fun(int x) {std::cout << (x + y) << std::endl; } int main() {hdmo a;//不同于命名空间,要使用类里的函数,需要先创建一个类a.Fun();return 0; }
-
在C++中struct也可以用于定义类,在升级了其功能的同时,也兼容C语言中的用法;即在C++中struct中也可以定义函数。
//C++中写法 struct ListNode {int val;ListNode* next; }; //C中写法 struct ListNode {int val;struct ListNode* next; };
在C语言中,由于struct仅为结构体的关键字,若要直接使用ListNode作为结构体类型,就必须借助typedef来重命名,但C++中,ListNode可以直接作为类的类型名,此处ListNode既可以说是一个类,也可以说是一个结构体。
访问限定符
C++⼀种实现封装的⽅式,⽤类将对象的属性与⽅法结合在⼀块,让对象更加完善,通过访问权限选择性的将其接口提供给外部的用户使用
- public关键字为公开,其修饰的成员在类的外部也可以直接被访问;protected和private修饰的成员在类外不能直接被访问,两者暂时理解为相同的意思,即为私密的。
- 访问限定符的作用域是从当前限定符开始,直到下一个限定符之前,若类中没有下一个访问限定符,则直接作用到‘ } ’类结束。
- class修饰的类,在没有使用访问限定符前默认的访问权限为private,而struct修饰的类,默认为public。
类域
类实际上也是定义了一个全新的作用域。类的所有成员都在类的作用域中,在类外部使用时都需要::来指名其所属的域,这和namespace命名空间有着一定的相似处。
当不指名成员所属的域时,默认就只会在全局作用域和当前作用域查找,若查找不到将会报错。
实例化
实例化概念:
使用类类型在物理内存中创建对象的过程,称为类实例化出对象。
-
类和结构体类似,在没有创建实体之前是不能直接使用其中的成员的,类就好比一个模板,规定了类中有那些成员,但也仅仅是声明了而已,并没有为其分配空间,只有实际创建了一个对象,即实例化出对象后,才会分配空间
-
一个类可以实例化出多个对象,就如一个结构体类型可以创建多个结构体变量一样,类就好比蓝图,一个图纸可以创建多个实体对象。
#include <iostream>
using namespace std;
class hdmo
{
public:void Print(){cout << _a << endl;}void Init(const int& x){_a = x;}
private:int _a;
};
int main()
{//hdmo::Print();//错误使用,区别于命名空间中的函数hdmo h1;//创建实例h1h1.Init(30);h1.Print();hdmo h2;//创建实例h2h2.Init(20);h2.Print();return 0;
}
对象大小:
和结构体一样,类创建的实例对象中包含了各种成员,但类中还包含了成员函数;每个实例化对象,都有自己的成员变量,他们是分别独立的,但成员函数呢?
无论是哪一个对象,在调用函数时,其使用的成员函数都必定是一样的,那么这还有必要在每一个对象中都放一个相同的函数吗?显然,是没有必要的,而且这样还会产生空间的浪费,如果有100个对象,就会产生100个相同的成员函数,造成空间的大量浪费。
成员函数在存储时会放在一个公共的代码区域,这样就只需要存储一份。
成员变量就和结构体中的成员变量一样,通过内存对齐的方式存储在对象中,而C++中的内存对齐和C语言是一模一样的。
内存对齐规则:
- 第一个成员放在偏移量为0的地址处;
- 其他成员变量要对齐到自身对齐数的整数倍的地址处;
- 对齐数 = 编译器默认对齐数 与 成员变量类型大小 取较小值;
- VS环境下默认对齐数为8;
- 对象(结构体)总体大小:成员中最大对其数(若最大对齐数超过默认值,则取默认值)的整数倍;
- 若嵌套了其他类的对象,则嵌套的类对象的对齐数为自身成员中的最大对齐数(相当于将嵌套的对象中的成员展开后对齐)
注意点:
#include <iostream>
using namespace std;
class hdmo1
{};class hdmo2
{void Print(){cout << "Printf" << endl;}
};int main()
{hdmo1 h1;hdmo2 h2;cout << sizeof(h1) << endl;//1cout << sizeof(h2) << endl;//1return 0;
}
当类为空,或者只包含成员函数时,此时用该类创建对象,对象的大小为1字节,用于表示对象的存在。
this指针
当我们使用类时,我们知道类创建对象后,对象的成员变量和成员函数是分开存储的,只有成员变量存储在对象中,而成员函数存储在其他地方并且函数体中没有关于不同对象的区分,那么,我们每次用不同的对象去调用相同的函数时,函数是如何知道应该访问的是d1对象还是d2对象呢?
以上问题,其实是C++中隐含了一个this指针来解决的。
演示代码(图中注释为真实原型,详见下文):
#include <iostream>
using namespace std;
class hdmo
{
public://void Init(hdmo* const this,int year, int month, int day)void Init(int year, int month, int day){_year = year;//this->_year = year;this->_month = month;this->_day = day;}//void Print(hdmo* const this)void Print(){cout << _year << "." << _month << "." << _day << endl;}
private:int _year;int _month;int _day;
};
int main()
{hdmo h1;//h1.Init(&h1, 2024, 7, 16);h1.Init(2024, 7, 16);//h1.Print(&h1);h1.Print();hdmo h2;h2.Init(2024, 7, 17);h2.Print();
}
在编译器编译后,类中的成员函数会默认在形参的第一个位置,添加一个当前类类型的指针,指针的名字为this;所以上述成员函数的真实原型为void
Init(hdmo* const this,int year, int month, int day)以及void
Print(hdmo* const this)在调用类的成员函数时,每次调用编译器会自动将调用的对象地址传到函数,this就是用于接收指定对象的地址的,成员函数中使用的成员变量实际上也是通过this指针找到的,即Init的赋值语句真实原型为this->_year
= year;this->_month;this->_day = day;C++中在日常使用时,规定this指针是由编译器编译时自动添加的,不能显示的写出来,但是在可以函数内部显示的使用this指针。
结语
本篇关于类和对象的学习介绍就先到这里了,本篇主要带领大家初始类和对象,在之后的博客中我们会再深入的讲解相关的知识,欢迎大家再来学习。
个人主页:海盗猫鸥-CSDN博客
本期专栏:C++_海盗猫鸥的博客-CSDN博客
那么本期就到这里,有不足或不正确的地方欢迎大家指出,大家早点休息,我们下篇博客再见——
~~O(∩_∩)O~~