在线设计平台canva可画/关键词seo排名优化推荐
10.类
1.面向对象编程语言的三大特性
- 封装
- 继承
- 多态
2.类
- 类 = 属性(数据) + 行为(函数)
- C语言中没有类的概念,但是可以通过结构体进行封装,但结构体中只能实现属性,并不能实现行为
struct student
{int nScore;int nClass;int nSex;
}
//c语言中可以实现属性的封装
student s1;
s1.nSex;
- C++中对此作了改进,C++中可以使用结构体或者类实现属性和行为的封装
struct student
{int nScore;int nClass;int nSex;void run(){printf("跑步");}
}
//c++中进一步可以实现行为的封装
student s1;
s1.run();
3.使用类或结构体实现封装的区别
- 类和结构体在C++中都可以实现封装,但是在访问权限上有所区别
- 类的定义中默认是私有权限
- 结构体的定义中默认公有权限
访问权限:
定义:指在当前类域之外访问的规则
(1)公有权限:在类域内部和类域外部均可访问
(2)保护权限:在继承中使用
(3)私有权限:在类域内部可以访问,但在类域外部不可以访问
//c++中使用结构体实现封装
//结构体中的属性和函数默认都是公有权限
struct student
{int nScore;int nClass;int nSex;void run(){printf("跑步");}
}
student s2;
s2.run();//可以访问
//c++中使用类实现封装
//类中如果未使用关键字对访问权限进行说明,默认是私有访问权限
class student
{int nScore;int nClass;int nSex;void run(){printf("跑步");}
}
student s1;
s1.run();//报错,私有访问权限外部无法访问
结构体与类的最大区别就是默认的访问权限不同
4.类的标准写法
- 1.类名前面一般加一个大写的C类名
- 2.类中包括数据成员和成员函数,其中数据成员一般称为member,所以在数据成员的名字前一般加上小写的m_名字
- 3.数据成员是类的属性,一般是私有访问权限,不希望用户直接修改类的属性,而希望通过部分的提供给用户具有公有访问权限的函数结接口对属性进行修改
- 4.我们一般只在类的定义中写成员函数的声明,而将类的成员函数的实现写在类的外部,并在成员函数前加上类的作用符
- 5.一般将类的定义写在头文件中,而将类中成员函数的实现写在cpp文件中
//头文件中
class CClock//类名前加C表示这是一个类
{
private:int m_hour;//类中数据成员的名称前加m_int m_minute;int m_second;
public://仅在类的定义中写成员函数的声明,函数实现在cpp文件中书写void setHour(int nHour);int getHour();
}
//cpp文件中
#include<包含类的定义的头文件>
void CClock::setHour(int nHour)
{//函数体功能
}
int CClock::getHour()
{//函数体功能
}
5.类的访问权限及C语言模拟类的封装
- 类的访问权限的检查时期:在编译时期进行类的访问权限的检查
- 一旦程序运行起来之后,在运行时期通过类的地址对类中私有数据成员进行访问和修改都不受限制,但是这种访问本质上是破坏了类的封装
class CClock
{//class默认是私有访问权限,在类域外不允许进行访问int m_Hour = 1;int m_Minute = 1;int m_Second = 1;
}CClock clock;
clock.m_Hour = 2;//报错,编译时期语法不通过
*(int*)&clock = 111;//这里需要特别注意,这种通过指针对类中的私有数据成员的值进行修改的操作,本质上破坏了类的封装
'''
&clock:取对象clock在内存中的地址
(int*)&clock:将对象clock的地址强制转换为(int*)的指针类型,其实就是强制将clock对象第一个数据成员的指针变为(int*)类型,方便后续对其进行解引用并赋int类型的值
*(int*)&clock = 111;对clock对象的首地址,即第一个数据成员进行解引用,并赋值为111
- 使用C语言来模拟类的封装,C中仅支持数据成员的封装,并不支持成员函数的封装,因此需要将成员函数变成一种数据成员,这里需要使用函数指针来实现
//定义函数指针
typedef void (*PFN_SetHour)(int n);
//在外部定义成员函数
void setHour( struct tagClock* c1,int n)
{c1->nHour = n;
}
//定义结构体
struct tagClock
{int nHour;int nMinute;int nSecond;PFN_SetHour pfnSetHour;//通过函数指针将成员函数变成数据成员
};int main()
{struct tagClock c1;c1.pfnSetHour = setHour;//对函数指针赋值c1.pfnSetHour(&c1, 1);//通过函数指针调用成员函数,但是需要传入结构体c1的地址,否则成员函数无法对结构体进行处理return 0;
}
需要注意的是,通过函数指针的形式,在结构体外部书写的成员函数与结构体的联系并不紧密,在使用成员函数实现具体功能是,成员函数中并不具有结构体中定义的数据成员,因此需要在调用成员函数的同时通过指针的方式给成员函数传入一个结构体