前言
本系列文章承接C语言的学习,需要有C语言的基础才能学会哦~
第3篇主要讲的是有关于C++的类的定义、访问限定符、类域、类的实例化和this指针。
C++才起步,都很简单呢!
目录
类
class为类的关键字,后跟类名,{ }中为类的主体。主体中内容称为类的成员,类中的变量称为类的属性或者成员变量,类中的函数称为方法或者成员函数。
基本语法
为了区分方法的形参和类中的成员变量,通常会在变量前后加一个下划线,具体怎么标识,看公司或者团队要求。
//类与对象
class Stack
{
//方法
void Init(int capacity = 4)
{
_array = (int*)malloc(sizeof(int) * capacity);
if (nullptr == _array)
{
perror("malloc申请空间失败!\n");
return;
}
_capacity = capacity;
_top = 0;
}
void Push(int x)
{
//扩容步骤(省略)
_array[_top++] = x;
}
//·······(省略栈的各种函数)
//成员变量
int* _array;
size_t _capacity;
size_t _top;
};
//类名就是类型
类中的成员函数,默认为inline函数。
访问限定符
①public公有,在类外可以直接被访问。设计时成员函数一般是公有的。
②private私有,在类外不能直接被访问。设计时成员变量一般是私有的。
③protect保护,在类外不能直接被访问。在继承上,和private有区别(在继承详细说明)。
基本语法
class Stack
{
//公有
public:
void Init(int capacity = 4)
{
_array = (int*)malloc(sizeof(int) * capacity);
if (nullptr == _array)
{
perror("malloc申请空间失败!\n");
return;
}
_capacity = capacity;
_top = 0;
}
//私有
private:
int* _array;
size_t _capacity;
size_t _top;
};
如上,跟在不同的访问限定符后,受不同的访问限定。
C++兼容C语言的struct,同时又升级了struct。
C++中,struct和类的唯一区别在于:struct的成员变量和方法默认为public,class默认为private。为求严谨,最好自己指明访问限定符。
//不加访问限定符,默认为public
struct Person
{
void Init(const char name[5])
{
strcpy(_name,name);
}
void Print()
{
cout << "姓名:" << _name << endl;
}
char _name[5];
};
int main()
{
//可在外部直接使用
Person p1;
p1.Init("张三");
p1.Print();
return 0;
}
类域
由类定义的一个新的作用域,类的所有成员都在类域中。类域使得不同的类可以有同名的成员。和命名空间类似,它影响的是编译器的查找顺序规则(具体去看我博客内的C++第一篇喔~)。
成员函数可以进行声明和定义的分离。
一般我们将声明放在类中,定义放在另一个文件中。并且为了标识该方法所属的类,需要用到域作用限定符 :: 。
void Stack::Init(int capacity)//注意定义处不要写缺省参数,缺省参数写在声明
{
//函数实现省略···
}
类的实例化
类中的成员变量在没有实例化时,均不开辟空间,只是一个声明。我们要将类实例化成对象后,它才能够存储数据,我们才能对具体的对象进行操作。
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;//实例化出对象d1
Date d2;//实例化出对象d2
d1.Init(2025, 7, 20);
d2.Init(2025, 7, 25);
d1.Print();
d2.Print();
cout << sizeof(d1) << endl;//输出12,成员变量共12个字节
cout << sizeof(d2) << endl;//输出12,成员变量共12个字节
return 0;
}
实例化后,对象只存储成员变量,不存储方法指针。因为同一类的对象使用的是相同的方法,所以将方法存储在公共代码区即可,不存储在实例对象里。否则,会重复存储,浪费空间。
内存对齐规则
成员变量存储,遵循C语言的内存对齐规则。
①第一个成员变量在类起始地址偏移量为0处。
②其他成员变量要对齐到对齐数的整数倍地址处。
③对齐数 = 编译器默认对齐数 与 该成员大小 的较小值。
④VS编译器默认的对齐数是8。
⑤类的总大小为默认对齐数的整数倍。
⑥类中没有成员时(如仿函数类),总大小为1byte。即使没有也要开辟空间占位,以表示存在实例对象。
内存对齐的目的:方便读取,读取数据时可以从在数据类型大小的整数倍位置读取,不用一字节一字节读,而是跳跃读取,找到位置后可以一次性读取,不用再一个字节一个字节拼起来。
this指针
用于指明类方法中区分访问的成员方法。类方法存储在公共代码区,在类方法的角度来看,调用它时,该方法并不清楚是哪个对象调用的它。这就要用到this指针。
类方法中实际上还会隐含一个参数,
void Init(int year, int month, int day)
{
//略···
}
//在形参列表首位,存在一个省略的参数this指针
void Init(Date* const this, int year, int month, int day)
{
//略···
}
我们可以看到有const修饰,该隐藏参数是不可以修改的。
调用时,会传入调用方法的对象的地址作为this指针
d1.Init(2025, 7, 21);
//d1.Init(&d1, 2025, 7,21);
//实际上是这样传参的,但是不能这样写
C++编译器会自动添加的隐含的this,程序员不可以自行添加,会报错。但是可以在函数体内添加使用。
void Print()
{
cout << _year << "/" << _month << "/" << _day << endl;
}
//等价于
void Print()
{
cout << this->_year << "/" << this->_month << "/" << this->_day << endl;
}
通过this指针,对象调用类方法时,才可以在类方法内访问对象的属性。
类指针的易错点:
class A
{
public:
void Print()
{
cout << "Hi!" << endl;
}
private:
int _a;
};
class B
{
public:
void Print()
{
cout << "Hi!" << endl;
cout << _b << endl;
}
private:
int _b;
};
int main()
{
//正常运行,输出“Hi!”
A* pa = nullptr;
pa->Print();
//运行崩溃
B* pb = nullptr;
pb->Print();
return;
}
如上,pa和pb都是空指针。
pa指针调用Print方法能正常运行,是因为运行时未对这个空指针进行解引用操作。
pb指针调用Print方法会运行崩溃,是因为运行到语句 cout << _b << endl 时,_b前有隐藏的this指针,所以这里实际上有一个 this->_b ,这里的this即是传入的pb空指针,发生解引用错误。
(“ 指针-> ”为解引用操作喔~)
ps:this指针的创建在栈区
封装(初步了解)
目的:C++将数据和函数放在类中,隐藏细节和复杂部分,只需要确保代码能实现目的即可。靠访问限定符,约束和管理程序员访问数据,避免细节上的错误。
关于封装更多的知识,在之后还有更多可以学习的,敬请关注!!
❤~~本文完结!!感谢观看!!欢迎来我博客做客~~❤