欢迎来到海盗猫鸥的博客~~
本篇我们将学习部分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;//创建实例h1
h1.Init(30);
h1.Print();
hdmo h2;//创建实例h2
h2.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;//1
cout << sizeof(h2) << endl;//1
return 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~~