作者:阿润菜菜
专栏:C++
目录
类和对象的定义
类的访问控制
类的作用域
this指针
思维导图:
前言
我们知道C++是基于面向对象的,关注的是对象,将一件事情拆分成不同的对象,靠对象之间的交互完成。而类(class)的引入是面向对象程序设计的最基本的概念,是进行封装和数据隐藏的工具。对象是现实世界中实体的抽象,类是对象的抽象,类是一种抽象数据类型。
类是抽象的,对象是具体的。比如:类是宠物,那橘猫就是对象
在C语言中,结构体中只能定义变量,而在在C++中,结构体内不仅可以定义变量,也可以定义函数。在结构体的定义,C++更喜欢用class 类来代替。
为什么c++要设计出类?
类是C++区别于C语言的一个重要的特性之一,类实现数据的封装、模块化,形象的说就相当一个模具,无论你想要制作多少个对象,只需要模具放入材料就可以制作出你想要的东西,而不像C语言那样每个既要给定材料,同时又要计算各方面数据。
class className
{
// 类体:由成员函数和成员变量组成
}; // 一定要注意后面的分号
class为定义类的关键字,ClassName为类的名字,{}中为类的主体,注意类定义结束时后面分
号不能省略。
类体中内容称为类的成员:类中的变量称为类的属性或成员变量; 类中的函数称为类的方法或者
成员函数。
类的两种定义方式:
1. 声明和定义全部放在类体中,需注意:成员函数如果在类中定义,编译器可能会将其当成内
联函数处理。
2. 类声明放在.h文件中,成员函数定义放在.cpp文件中,注意:成员函数名前需要加类名::
一般情况下,我们更期望采用第二种方式
class Date
{
public:
Date(int year=1900, int month=1, int day=1); //构造函数
void Print();
int GetMonthDay(int year, int month);
bool operator==(const Date& d); //设为const 权限缩小 防止数据误操作
bool operator!=(const Date& d);
bool operator>(const Date& d);
bool operator>=(const Date& d);
bool operator<(const Date& d);
bool operator<=(const Date& d);
//d1 -=100;
Date& operator+=(int day); //返回引用 自身改变
Date operator+(int day); //自身不改变
Date& operator-=(int day);
Date operator-(int day);
//++d1;
Date& operator++();
//d1++
Date& operator++(int); //占位参数 int 与前置重载区别 编译器会根据占位参数区分
private:
int _year;
int _month;
int _day ;
};
为什么成员变量定义喜欢加_? 防止成员函数参数与成员变量名字冲突
对于成员变量命名规则的建议:成员变量一般都是加个前缀或者后缀标识区分
类和对象的关系:
类是对象的抽象,而对象是类的具体实例。类是抽象的,不占用内存,而对象是具体的,占用存储空间。类是用于创建对象的蓝图,它是一个定义包括在特定类型的对象中的方法和变量的软件模板。
类与对象的关系就如模具和铸件的关系 类的实例化结果就是对象,而对一类对象的抽象就是类,类描述了一组有相同属性和相同方法的对象。
类是声明(相当于设计图),类对象实例化 ----开辟空间 才可以使用
如何计算类对象所占内存的大小?
成员变量在对象中(对象实例化开辟的空间中),成员函数不在对象中(成员函数因为公用属性,存储在代码段中) 所以计算一个类对象,只需要计算成员变量的总大小(同时考虑结构体内存对齐规则)
每个对象调用的成员函数是一样的,放到共享公共区域(代码段)
空类(即没有任何成员变量)实例化对象的大小是1字节
C++实现封装的方式:用类将对象的属性与方法结合在一块,让对象更加完善,通过访问权限选择性的将其接口提供给外部的用户使用
封装(面向对象三大特性之一):C++的封装 数据和方法都封装到类里 可以控制访问方式 公有的给你访问,私有的不给你访问;
访问限定符说明
1. public修饰的成员在类外可以直接被访问
2. protected和private修饰的成员在类外不能直接被访问(此处protected和private是类似的)
3. 访问权限作用域从该访问限定符出现的位置开始直到下一个访问限定符出现时为止
4. 如果后面没有访问限定符,作用域就到 } 即类结束。
5. class的默认访问权限为private,struct为public(因为struct要兼容C)
注意:访问限定符只在编译时有用,当数据映射到内存后,没有任何访问限定符上的区别
问题:C++中struct和class的区别是什么?
解答:C++需要兼容C语言,所以C++中struct可以当成结构体使用。另外C++中struct还可以用来定义类。和class定义类是一样的,区别是struct定义的类默认访问权限是public,class定义的类默认访问权限是private。注意:在继承和模板参数列表位置,struct和class也有区别,后序给大家介绍。
类定义了一个新的作用域,类的所有成员都在类的作用域中。
在类的作用域之外
//pos成员(类型别名)在类Screen的作用域内
Screen::pos ht = 24, wd = 80;
Screen scr(ht, wd, ' '); //类名 构造函数,构造出窗口scr
Screen *p = &scr;
char c = scr.get(); //访问scr对象的get成员
c = p->get(); //访问p所指对象的get成员
//等价于 c = (*p).get()
作用域和定义在类外部的成员
class Window_mgr{
public:
//向窗口添加一个Screen,返回它的编号 (返回类型为ScreenIndex)
ScreenIndex addScreen(const Screen&);
...
};
//返回类型在Window_mgr类的作用域之外,要想使用ScreenIndex作为返回类型,必须指定哪个类定义了该返回类型
//addScreen函数在Window_mgr类的作用域之内
Window_mgr::ScreenIndex Window_mgr::addScreen(const Screen &s){
screens.push_back(s);
return screens.size() - 1;
}
引出
如果Date类中有 Init 与 Print 两个成员函数,函数体中没有关于不同对象的区分,那当d1调用 Init 函数时,该函数是如何知道应该设置d1对象,而不是设置d2对象呢?
C++中通过引入this指针解决该问题,即:C++编译器给每个“非静态的成员函数“增加了一个隐藏的指针参数,让该指针指向当前对象(函数运行时调用该函数的对象),在函数体中所有“成员变量”的操作,都是通过该指针去访问。只不过所有的操作对用户是透明的,即用户不需要来传递,编译器自动完成。
即this是当前这个对象的指针,哪个对象调用*this就修饰哪个对象
this指针的特性
1 . this指针的类型:类类型* const,即成员函数中,不能给this指针赋值。
2. 只能在“成员函数”的内部使用
3. this指针本质上是“成员函数”的形参,当对象调用成员函数时,将对象地址作为实参传递给this形参。所以对象中不存储this指针。
4. this指针是“成员函数”第一个隐含的指针形参,一般情况由编译器通过ecx寄存器自动传递,不需要用户传递5.this指针的添加和使用的操作在源码层面是不可见的,都是编译器在编译阶段自动完成的。但通过汇编可以很清楚地看到this指针的存在。
问题1 this存在哪里?
存在栈上,因为this是成员函数隐含形参 (vs下面是通过ecx寄存器) 注意不要与函数体存在代码段混淆,函数参数和函数体不是一类东西,函数参数会在函数调用结束后进行销毁
问题2 this指针可以为空吗?
这里注意对象函数是在代码段里(没有在对象里面),ptr->func并没有解引用(有没有解引用取用于你要访问的东西有没有在对象里,要不要去对象里寻找),ptr->Init()访问后this指针指向为空,找不着成员变量,程序会崩溃
(*ptr)func()为什么可以正常运行? 虽然ptr为空指针,但是func()不在对象里,this即使收到空指针但仍能访问成员函数
为什么不能直接调用func() ? 因为有类作用域问题
下一节>>>
当然 类和对象中最重要的就是 类的成员函数知识