1. 类的定义和对象的创建
1.1 类的定义
- 语法:
class 类名{ 访问权限:属性/行为 };
其中,class
是专门用来专门定义类的关键字, 类名 一般首字母大写。{ }
内部是类的成员,包括成员变量和成员函数。
注意: 类定义的最后有一个分号;
,表示定义结束,不能省略。
示例:创建一个Person
类
class Person
{
public:
//成员变量
char *m_name;
int m_age;
//成员函数
void show()
{
cout << m_name << ", " << m_age << endl;
}
};
1.2 创建对象
- 利用类直接创建对象:
Person man; // Person为类名,per为对象名
- 栈上创建对象:
Person *p1 = &man;//对象指针
- 堆上创建对象:
Person *p2 = new Person;//对象指针
1.3 访问对象
对象名.成员名
对象指针->成员名
说明: 对象指针访问成员变量也可以用.
,但是没有->
方便。
具体操作:(*对象指针).成员名
,如(*p1).m_name
。需要注意的是:*p1
两边的库号不能省略,因为.
的优先级高于指针运算符*
,如果去掉括号,*p1.m_name就等价于*(p1.m_name)
。
2. 成员变量和成员函数
2.1 类的成员变量
类的成员变量和普通变量一样,要有数据类型和变量名称。但是,定义类时不能对成员变量赋值,因为类时一种模板,本身不占有内存,而变量的值则需要内存来存储。
2.2 类的成员函数
类的成员函数根据其定义的位置可以分为类内成员函数和类外成员函数。
- 类内成员函数,直接在类体中定义。
- 类外成员函数是类体内声明,类外定义。在类外定义成员函数时,需要指明函数属于哪个类。用域操作符
::
,连接类名和函数名,如void Person::show(){cout << m_name << ", " << m_age << endl;}
。
3. 访问权限设置
设计类时,可以把属性和行为放在不同的权限下,加以控制。访问权限有三种:
- public 公共权限:类内可以访问,类外可以访问
- protected 保护权限:类内可以访问,类外不可以访问
- private 私有权限:类内可以访问,类外不可以访问
将所有成员属性设置为私有属性,可以控制读写权限。利用读写权限可以检测数据的有效性。
4. 构造函数和析构函数
构造函数和析构函数负责解决对象的初始化和清理工作。
4.1 构造函数
构造函数:主要作用在于创建对象时为对象的成员属性赋值,构造函数由编译器自动调用,无须手动调用.
4.1.1 构造函数语法
语法:类名(){ }
- 构造函数,没有返回值,也不能写void
- 函数名与类名相同
- 可以有参数,因此可以发生重载。一个类可以有多个重载的构造函数
- 程序在调用对象时会自动调用构造函数,无须手动调用,且只调用一次。
4.1.2 构造函数的分类
两种分类方式:
- 按参数分:有参构造和无参构造
- 按类型分:普通构造和拷贝构造
拷贝构造函数是一种特殊的构造函数,函数的名称必须和类名称一致,它的唯一的一个参数是本类型的一个引用变量,该参数是const类型,不可变的。例如:Person (const Person& p)
。
4.1.3 构造函数的调用规则
默认情况下,C++编译器至少给一个类提供3个函数:
- 默认构造函数(无参,函数体为空)
- 默认析构函数(无参,函数体为空)
- 默认拷贝构造函数,对属性进行值拷贝
构造函数调用规则:
- 如果用户定义有参构造函数,c++不在提供默认无参构造,但是会提供默认拷贝构造
- 如果用户定义拷贝构造函数,c++不会再提供其他构造函数
4.1.4 构造函数的初始化列表
除了在构造函数的函数体中对成员变量一一赋值,还可以采用初始化列表。
示例:
class Person
{
public:
Person(char *name, int age);
private:
char *m_name;
int m_age;
};
//初始化列表
Person::Person(char *m_name, int age):m_name(name),m_age(age){}
定义构造函数时并没有在函数体中对成员变量一一赋值,其函数体为空(当然也可以有其他语句),而是在函数首部与函数体之间添加了一个冒号:,后面紧跟m_name(name), m_age(age)语句。
注意,成员变量的初始化顺序与初始化列表中列出的变量的顺序无关,它只与成员变量在类中声明的顺序有关
.
构造函数初始化列表还有一个很重要的作用,那就是初始化 const 成员变量。初始化 const 成员变量的唯一方法就是使用初始化列表。
4.2 析构函数
析构函数:主要作用在于对象销毁前系统自动调用,执行一些清理工作。
4.2.1 析构函数语法
语法:~类名(){}
- 析构函数,没有返回值,也不能写void
- 函数名与类名相同,函数名前要有符号
~
- 析构函数不可以有参数,不会发生生重载
- 程序在对象销毁前会自动调用析构函数,无须手动调用,且只会运行一次。
5. this指针与const修饰成员变量
5.1 this 指针
C++中特殊的对象指针,this指针指向被调用的成员函数锁住的对象。
this指针是隐含每一个非静态成员函数内的一种指针。this指针不需要定义,直接使用即可。
this指针的用途:
- 当形参和成员变量同名时,可用this指针进行区分
- 在类的非静态成员函数中返回对象本身,可使用return *this
this指针的本质是一个指针常量,指针的指向不可修改。
5.2 const修饰成员变量
前面提到,隐含在成员函数中都有一个this指针。this指针的指向是不可以修改的,但是指向的值可以修改,例如Person * const this
。如果想让指向的值也不可以修改,需要再加一个const。反映到成员函数上,最终加在成员函数的后面。
- 常函数
- 成员函数后面加const,称这个函数为常函数
- 常函数内不可以修改成员属性
- 成员数性声明时加关键字mutable后,常函数中依然可以修改。
在成员函数后面加const的本质是修饰this指针,让指针指向的值不可以修改。
如果变量特殊,成员属性声明时加关键字mutable,常函数中依然可以修改。
- 常对象
- 声明对象前加const,称该对像为常对象
- 常对象只能调用常函数
6. 静态成员
静态成员就是在成员变量和成员函数前加上关键字static,称为静态成员。
- 静态成员变量
- 所有对象共享同一份数据
- 在编译阶段分配内存
- 类内声明,类外初始化,初始化形式:
type class::name = value
- 静态成员函数
- 所有对象共享同一个函数
- 静态成员函数只能访问静态成员变量