1.类的定义
1.1 类的格式
①class为类的关键字
②在类的内容中还可以写函数,具体格式请看示例。
③为了区分成员变量,一般习惯上成员变量会加一个特殊标识(如成员变量前面或者后面加_ 或者 m开头,注意C++中这个并不是强制的,只是一些惯例,具体看公司的要求)
④C++中struct也可以定义类,但是一般情况下还是用class来定义类。
⑤C++中语法,struct在C语言中的用法兼容。
⑥在类中定义的成员函数默认是inline。
class stack
{
//这里也可以写函数
void Init(int capacity = 4)
{
//此处省略
}
//成员变量
int* _array;
//...
};
int main()
{
stack st1;//直接用类名来定义对象
//初始化
st1.Init();
return 0;
}
④的示例:
struct Person
{
public:
void Init(const char* name, int age, int tel)
{
//写内容
}
private:
char _name[10];
int _age;
//...
};
//类名就是类型
1.2 访问限定符
①public修饰的成员在类外可以直接被访问;;protected和private修饰的成员在类外不能直接被访问。
②访问权限作用域从该访问限定符出现的位置开始直到下一个访问限定符出现时为止,如果后面没有访问限定符,作用域就到 }即类结束。
③class默认为private,struct默认为public。
④一般类中的函数是public, 成员变量是private。
示例:
class stack
{
public:
//这里也可以写函数
void Init(int capacity = 4)
{
//此处省略
}
//成员变量
private:
int* _array;
//...
};
int main()
{
stack st1;//直接用类名来定义对象
//初始化
st1.Init();
return 0;
}
1.3 类域
类定义了一个新的作用域,所有成员都在类的作用域中,在类外定义成员时,需要使用::作用域操作符还指明成员属于哪个作用域。
例如:
class Stack
{
public:
void Init()
{
}
private:
int* _a;
int _name;
int _age;
};
class Queue
{
public:
void Init()
{
}
};
此时两个类域中都有相同的变量名,因此,需要使用操作符来进行限制。不然就会出现报错。
2.实例化
2.1 概念
①用类类型在物理内存中创建对象的过程,称为类实例化出对象。
②限定了类有哪些成员变量,这些成员变量只是声明,没有创建空间。
③类可以实例出多个对象,占有实际的物理空间,存储类成员变量(不存函数类型)。
(没有成员变量的类对象,开1byte,占位,不存储有效数据,为了标识对象的存在。)
图解释:
(图形仅供参考)
内存对应规则:
内存对齐其实会浪费空间,为啥还要用这种规则?
3.this指针
①编译器编译后,类的成员函数默认都会在形参第一个位置,增加一个当前类类型的指针,叫做this指针。(比如Date类的Init的真实原型为, void Init(Date* const this, int year,
int month, int day))②访问成员变量,本质上是用this指针来访问的。(如Init函数中给_year赋值, this-
>_year = year;)③C++规定不能在实参和形参的位置显示的写this指针(编译时编译器会处理),但是可以在函数体内显示使用this指针。
#include<iostream>
using namespace std;
class A
{
public:
void Print()
{
cout << "A::Print()" << endl;
}
private:
int _a;
};
int main()
{
A* p = nullptr;
p->Print();
return 0;
}
在这个代码中,成员函数的指针是在编译时确定的,没有存在对象中,所以这里虽然写了p->,但是没有解引用。
class A
{
public:
void Print()
{
cout << "A::Print()" << endl;
cout << _a << endl;//不同
}
private:
int _a;
};
int main()
{
A* p = nullptr;
p->Print();
return 0;
}
这个代码是运行崩溃,因为在
cout << _a << endl
中,其实存在 this -> _a,所以此时是错误的。
综上所述,指针存在于内存的栈中(隐含的形参)。
VS系列编译器,this通过寄存器ecx传递。
4.C++和C语言实现Stack对比
面向对象三大特征:封装、继承、多态
①C++封装:数据和函数都放在类中,通过访问限定符进行了限制,不能随便通过对象直接修改数据(最重要的变化)。
② 实质差异没有那么大,见后续的学习。
5.类的默认成员函数
定义:编译器默认生成的函数
一共有六个(后续会增加)
见以下的图:
(图片来自于比特就业课,仅供参考)
5.1 构造函数
构造函数是特殊的成员函数,主要任务是对象实例化时初始化对象。
特点:
①函数名和类名相同
②无返回值
③对象实例化时系统会自动调用对应的构造函数
④构造函数可以重载
⑤如果类中没有显式定义构造函数,则C++编译器会自动生成一个无参的默认构造函数,一旦用户显式定义编译器将不再生成
⑥无参构造函数、全缺省构造函数、编译器默认生成的构造函数,都叫默认构造函数;有且仅有一个存在,不会同时存在。(不传实参就可以调用的构造就叫默认构造函数)
⑦是否初始化要看我们的编译器。对于自定义类型的成员变量,要求调用这个成员变量的默认构造函数初始化。如果没有默认构造函数,就会报错
C++把类型分成内置类型和自定义类型。
内置类型就是语言提供的原生数据类型(如:int/ char/ double/ 指针等)
自定义类型就是我们使用class/ struct等关键字自己定义的类型
特点例子:
class Data
{
public:
Data()
{
_year = 1;
_month = 1;
_day = 1;
}
Data(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()
{
Data d1;
Data d2(2024, 8, 5);
d1.Print();
d2.Print();
return 0;
}
而此时的运行结果是:
全缺函数在这里应用会更加方便。