1. 类和对象提出的背景
c语言是面向过程的语言,关注解决问题的过程,利用函数逐步解决。这种方式在解决大型问题上会显得麻烦,所以,c++在c语言的基础上,提出了类和对象。
即c++基于面向对象,将一个问题拆分为不同的对象,通过对象之间的交换完成
举一个例子:在c语言中,人吃菜通过一个个步骤,先将筷子放到菜上方,再用筷子夹菜,再将筷子向嘴巴的方向移动......;而在c++中,吃菜这个问题就变成人、菜、筷子这三个对象之间的交互,不关注筷子具体如何夹菜这一过程。
2. 类的引入和定义
2.1 类的引入
在c语言中,结构体内只能定义变量,而在c++使用struct会发现,结构体不仅可以定义变量,还可以定义函数。只是c++中更喜欢用class(类)来代替结构体
类的定义:
class class_name
{
//类体:成员变量和成员函数
}; //注意分号
//class为定义类的关键字,class_name为类的名字
//类体中内容称为类的成员
类的成员:变量称为类的属性或成员变量;函数称为类的方法或成员函数
2.2 类的定义方式
2.2.1 类中声明和定义
class Date
{
public:
int _year;
int _month;
int _day;
public:
void print()
{
cout << _year << "-" << _month << " " << _day;
}
};
声明和定义全部放在类中,但注意:如果成员函数在类中定义,编译器可能会将其当成内联函数(之后介绍)处理。
(对于public下文会介绍)
2.2.2 类中声明,类外定义
class Date
{
public:
int _year;
int _month;
int _day;
public:
void print();
};
//注意函数名前加 类名::
void Date::print()
{
cout << _year << "-" << _month << " " << _day;
}
其中,声明可以放.h文件中,定义放.cpp文件中。这种方式是更期望使用的
3. 类成员的命名规则建议
//不建议的
class Date
{
private:
int year;
public:
void Init(int year)
{
//这样命名对于成员变量和函数形参的分辨不友好
year = year;
}
};
//建议的
class Date
{
private:
int _year;
public:
void Init(int year)
{
//很容易分辨
_year = year;
//其他方式也可以,比如前缀或后缀
}
};
4. 类的封装和访问限定符
4.1 封装的介绍
面向对象的三大特性:封装、继承、多态
在类和对象,主要研究类的封装特性。
封装:将数据和操作数据的方法结合,隐藏对象的属性和实现细节,仅公开接口来和对象交互
c++可以通过访问权限来实现隐藏对象内部实现的细节,让方法可以在类外直接调用
这种封装管理可以让我们更方便、更安全地使用类,不用担心不小心访问改变了类的细节而报错,可以简单直接关注如何使用类交互
4.2 访问限定符
访问限定符是c++实现封装的方式:类将对象的属性和方法结合,通过访问限定控制接口给外部的用户
访问限定符:public(公有)、protectde(保护)、private(私有)
注释:1. public修饰的成员可以在类外直接访问
2. protect和private修饰的成员变量在类外不可以直接访问(这里二者相似)
3. 访问权限的作用域从该访问限定符出现开始到下一个访问限定符出现为止,如果后面没有访问限定符,到 } 结束
4. class的默认访问权限为private,struct的默认权限为public(这里考虑兼容c语言)
5. 类的实例化和对象模型
5.1 类的实例化
实例化:用类类型创建对象的过程
类是对对象进行描述如同模型一样的东西,限定了类的成员,进行声明,但并没有实际分配内存空间进行存储。可以比作建房子,类就相对于图纸,对象是实际建出的房子,图纸不占空间,只有设计出的房子才占空间。同时,一个图纸可以建设多个房子。同理,一个类可以实例化多个对象
5.2 类对象存储和大小
5.2.1 类对象存储方式
我们可以思考一下:每个对象成员变量不同,但调用同一份函数。如果类中包含各个成员(包括成员函数),那类创建多个对象时,就会保存相同的代码多次,浪费空间。所以,类对象只保存成员变量,成员函数放公共代码段。
验证:
class A1
{
public:
void f(){}
private:
int _a;
};
class A2
{
public:
void f2(){}
};
class A3
{
};
//A2(仅有成员函数)和A3(空类)存储一样大,编译器会给空类一个字节标识这个类对象
所以,一个类的大小实际是该类 ”成员变量“ 大小的和(注意内存对齐)
6. 类的作用域
类定义了一个新的作用域,类的所以成员都在类的作用域中。类外定义成员时,使用::(作用域限定符)指明成员的所属类域
class Date
{
public:
int _year;
int _month;
int _day;
public:
void print();
};
//注意函数名前加 类名:: 指明所属类域
void Date::print()
{
cout << _year << "-" << _month << " " << _day;
}
7. this指针
7.1 引出
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;
};
对于 Init 和 print 成员函数,函数中没有关于不同对象的区分,只有要设置的参数,那使用函数时,如何区分不同的对象呢?
c++引用了 this 指针,即:c++编译器给每个”非静态成员函数“(之后介绍)增加了一个隐藏的指针参数,让这个指针指向当前对象,在函数中所有”成员变量“的访问,都通过该指针访问。只不过这个指针不需要用户传递,编译器自己完成
7.2 this指针的性质
1. this指针的类型:类 类型*const(即不能给this指针赋值)
2. 只能在”成员函数“内部使用,不能显示传递
3. this指针本质是”成员函数“的形参,当对象调用成员函数时,将对象地址传递给形参,对象不存储this指针(this指针存在栈中)
4. this指针是”成员函数“第一个隐式的指针形参,编译器自己传递,不需要用户传递
//隐藏
void print()
{
cout << _year << endl;
}
//实际
void print(Date*this)
{
cout << this->_year << endl;
}