戴尔网站建设的特点,广西城市网,九冶建设有限公司官方网站,长春建设厅官方网站本文已收录至《C语言》专栏#xff01; 作者#xff1a;ARMCSKGT 目录
前言
正文
面向过程与面向对象
面向过程的解决方法
面向对象的解决方法
面向对象的优势
类的引入
早期C类的实现
class定义类
class定义规则
类成员的两种定义方式
类的访问限定符及封装
访… 本文已收录至《C语言》专栏 作者ARMCSKGT 目录
前言
正文
面向过程与面向对象
面向过程的解决方法
面向对象的解决方法
面向对象的优势
类的引入
早期C类的实现
class定义类
class定义规则
类成员的两种定义方式
类的访问限定符及封装
访问限定符
封装
类成员
成员变量
成员函数
类的实例化
实例化概念 类的实例化方法
类对象大小
变量与方法的空间
类的大小
this指针
this指针的引入
this指针特性
this空指针
最后 前言
C在C语言的基础上增加了面向对象的特性有了类的概念使其解决问题的焦点从解决过程转变为解决对象对于C来说任何事物皆为对象从这里开始我们正式进入面向对象的大门 正文 在C语言编程中我们更加注重解决问题的过程每一步的解决方法 而在C语言编程中我们更加注重解决问题的对象解决问题需要哪些对象参与 面向过程与面向对象 为了更加深入的介绍面向过程和面向对象的区别我们举一个洗衣服的例子 面向过程的解决方法 面向对象的解决方法 可以看出来面向对象的解决方法侧重于建立对象模型然后针对对象建立方法构建出对象之间的关系然后解决问题所以面向对象更关注问题的本身 面向对象的优势 面向对象具有三大特性封装继承和多态 面向对象的优点易维护易复用易扩展 综合而言面向过程的思想无法满足大型项目问题的解决面向对象才是解决大型项目问题的最佳选择 本篇文章主要介绍面向对象的三大特性之一封装 类的引入 在C中对象非常重要而对象的创建就需要类 早期C类的实现 在C中每个对象都是一个类。早期C的类可以由结构体来写C语言结构体中只能定义变量在C中结构体内不仅可以定义变量也可以定义函数。 //C语言结构体
struct stu
{int num; //只能定义变量char ch;
}; //C结构体
struct stu
{int Add(int a, int b); //声明函数void swap(int* left, int* right) //定义函数{int tmp *left;*left *right;*right *left;}int num; //定义变量
}; 但是struct的成员项默认是public(公开)权限C为了兼容C不能修改结构体的性质但是公开的访问权限这不太符合封装的要求于是C重新定义一个关键字class来定义类 class定义类 class定义规则 在C中新增class关键字来定义类class定义的类中可以写函数声明函数定义以及变量但是其访问限权默认为private(私有)。 //格式
class 类名
{//类成员函数声明(使用头文件声明与定义分离时声明函数);int Print();//成员函数定义(实现)int Add(int a,int b){return ab;}//成员变量int num;}; //与结构体一样需要带一个分号class为定义类的关键字ClassName为类的名字{}中为类的主体注意类定义结束时后面分号不能省略。 类体中内容称为类的成员类中的变量称为类的属性或成员变量; 类中的函数称为类的方法或者成员函数。 类成员的两种定义方式 函数定义在类中 声明和定义全部放在类体中需注意成员函数如果在类中定义编译器可能会将其当成内 联函数处理在实例化时会在调用处直接展开 函数声明与定义分离 当类声明放在.h文件中成员函数定义放在.cpp文件中时由于类定义了新的作用域类的所有成员都在类的作用域中。在类体外定义成员时需要使用 :: 作用域操作符指明成员属于哪个类域既成员函数名前需要加 类名:: 一般情况下更期望采用第二种方式。因为在工作中经常声明与定义分离 类的访问限定符及封装 C实现封装的方式用类将对象的属性与方法结合在一块让对象更加完善通过访问权限选择性的将其接口提供给外部的用户使用。 访问限定符 class Test
{
public://从该行开始内容公开限制区域直到碰到下一个访问限定符// 函数/函数声明以及允许用户调用的接口// ......private://从该行开始内容私有// 变量/数据-不允许用户接触的函数接口和数据一般类成员变量都是该限定符//......
}; 在 class 中有三种访问限定修饰符 public 公有可以在类外直接访问其成员protected 保护能在类中被访问也能在其派生类中被访问private 私有被修饰成员只能在类中访问 说明 protected和private修饰的成员在类外不能直接被访问(此处protected和private是类似的在类继承时有区别)。访问权限作用域从该访问限定符出现的位置开始直到下一个访问限定符出现时为止如果后面没有访问限定符作用域就到 } 即类结束。class的默认访问权限为privatestruct为public(因为struct要兼容C且C中的struct也可以使用访问限定符)。访问限定符只在编译时有用当数据映射到内存后没有任何访问限定符上的区别。 struct和class的区别 C需要兼容C语言所以C中struct可以当成结构体使用。另外C中struct还可以用来定义类。和class定义类是一样的区别是struct定义的类默认访问权限是publicclass定义的类默认访问权限是private。在继承和模板参数列表位置struct和class也有区别后序给大家介绍封装 前面我们提到过面向对象的三大特性是封装、继承、多态在类和对象阶段主要是研究类的封装特性。 封装将数据和操作数据的方法进行有机结合隐藏对象的属性和实现细节仅对外公开接口来和对象进行交互。 封装本质上是一种管理让用户更方便使用类。比如对于电脑这样一个复杂的设备提供给用户的就只有开关机键、通过键盘输入显示器USB插孔等让用户和计算机进行交互完成日常事务。但实际上电脑真正工作的却是CPU、显卡、内存等一些硬件元件。 对于计算机使用者而言不用关心内部核心部件比如主板上线路是如何布局的CPU内部是如何设计的等用户只需要知道怎么开机、怎么通过键盘和鼠标与计算机进行交互即可。因此计算机厂商在出厂时在外部套上壳子将内部实现细节隐藏起来仅仅对外提供开关机、鼠标以及键盘插孔等让用户可以与计算机进行交互即可。 在C语言中实现封装可以通过类将数据以及操作数据的方法进行有机结合通过访问权限来隐藏对象内部实现细节控制哪些方法可以在类外部直接被使用。 类成员 类中的变量和函数位置可以颠倒编译器会在类中进行查找 成员变量 在class中定义内置类型变量和自定义类型变量称为成员变量为了安全一般使用private修饰 由于每个实例化出来的对象都有属于自己的成员变量在类相互联系调用时难免会发生调用的函数参数名与变量名相同的情况为了更好的辨别一般在变量名前加上下划线 _ 以示区分 //日期类
class Date
{
public:void Input(size_t year,size_t month,size_t day)//函数参数与变量名相似{cout 请依次输入年月日 endl;cinyear;cinmonth;cinday;}private:size_t _year; //变量名前加_size_t _month;size_t _day; //size_t是无符号整型
}; 成员函数 在C中类最显著的特性就是可以封装函数在类中的函数称为成员函数或方法。 对于同类型的类对象其方法是相互共享的并不是每个对象都有独立的函数代码因为成员函数虽然定义在类中但实际上这些成员函数的代码处于代码段每个对象需要调用时通过地址去调用函数。 //日期类
class Date
{
public:Date()//构造函数:_year(1970), _month(1), _day(1){}void Print()//简单打印日期{cout _year endl;cout _month endl;cout _day endl;}private:size_t _year;size_t _month;size_t _day;//size_t是无符号整型
};int main()
{Date d1; //实例化Date类d1.Print();
} 所以每个对象的方法是共享的数据是相互独立的 类的实例化 用类类型创建对象的过程称为类的实例化 实例化概念 类是对对象进行描述的是一个模型一样的东西限定了类有哪些成员定义出一个类并没 有分配实际的内存空间来存储它比如入学时填写的学生信息表这个表格先在电脑上设计出来此时表格就可以看成是一个类打印出来学生填写后就可以描述具体学生信息。 一个类可以实例化出多个对象实例化出的对象占用实际的物理空间存储类成员变量。 所以类是不能直接使用的必须实例化出对象才能使用因为类就相当于一张造房子的图纸我们想得到房子必需按照图纸进行建造而不是直接住进图纸里 类的实例化方法 类的实例化与结构体相似只不过类使用类名定义变量即可不需要typedef重定义类型 //创建对象
class Test {} //举例类int main()
{Test t;//实例化类为对象treturn 0;
} 类对象大小 变量与方法的空间 类可以产生多个对象这些对象共用代码段中的所属类方法好比小区中有很多套房子(房子就是对象)房子中住着很多居民(居民就是数据)小区的保安超市和健身器材等都是公共的(这些公共资源就是方法)每个居民可以根据自己所需进行资源的使用这样就避免了资源浪费毕竟小区如果每个人都安排独立的超市那么是非常不合理的 类的大小 在上面我们提到过类的字节大小不包括函数方法只包括变量数据所以类的大小计算是以每个成员变量的大小进行内存对齐相加就是类的大小与C语言结构体大小计算相同 class Test
{
public:Test() :_str(Test num:), _num(10){}void Print(){cout _str _num endl;}private:char _str[15]; //15字节int _num; //4字节
};int main()
{Test t;cout Test: sizeof(Test) endl;cout t: sizeof(t) endl;t.Print();return 0;
} 运行结果 0-14字节是_str的空间15不是4的倍数_num从16字节开始占用4个字节即16-19以最大对齐数4整数倍对齐总大小即20字节。 内存对齐说明 第一个成员在与结构体偏移量为0的地址处。其他成员变量要对齐到某个数字对齐数的整数倍的地址处(注意对齐数 编译器默认的一个对齐数 与 该成员大小的较小值。VS中默认的对齐数为8)。结构体总大小为最大对齐数所有变量类型最大者与默认对齐参数取最小的整数倍。如果嵌套了结构体的情况嵌套的结构体对齐到自己的最大对齐数的整数倍处结构体的整体大小就是所有最大对齐数含嵌套结构体的对齐数的整数倍。注意空类(不含任何成员变量)的大小为1字节这1个字节并不用来存储数据只是用来唯一标识这个类的对象表示类对象实例化后的存在 this指针 this指针的引入 类实例化的对象每个对象都有自己独立的变量成员不同的对象调用同一个函数时为了区分便加入了this指针方便访问该对象的成员变量 类的成员函数中编译器会在编译时为每个函数的参数中添加了this指针当我们使用某个实例化对象调用类成员函数时在这个函数内this指针指向调用该函数对象(存储的是该对象的地址)这样成员函数就可以直接访问该对象的变量成员而不需要定义额外的参数 //示例-this指针调用原理
class Test
{
public:void Print(Test* const this) //实际上编译器会在函数参数中会隐式定义this指针{cout this-_num endl;}
private:int _num;
};int main()
{Test t1,t2;t1.Print(t1); //对象调用函数时会将自己的地址隐式传递给函数t2.Print(t2);return 0;
} 由于这种行为是编译器自动执行的我们无法去干预(例如自己显示定义) //证明this指针
class Test
{
public:Test(int num 0) :_num(num){}void PrintA() //可以隐式调用成员变量{cout _num _num endl; //与this-_num效果相同}void PrintB() //也可以显示使用this指针调用成员变量{cout _num this-_num endl;}
private:int _num;
};int main()
{Test t(1);t.PrintA();t.PrintB();return 0;
} 代码运行结果 代码的运行结果说明了两点首先this指针是真实存在的可以调用对象的成员变量而且我们在使用成员变量是可以使用this指针指明要使用成员变量(显示使用this指针)也可以直接使用成员变量(编译器隐式使用this指针)。 C中通过引入this指针解决了同一个函数中区分不同对象的问题即C编译器给每个“非静态的成员函数“增加了一个隐藏的指针参数让该指针指向当前对象(函数运行时调用该函数的对象)在函数体中所有“成员变量”的操作都是通过该指针去访问。只不过所有的操作对用户是透明的即用户不需要来传递编译器自动完成this指针主要是为了区分一个函数中的不同对象。 //示例-this指针所解决的问题
class Test
{
public:void subtract(const Test pt) //求两个对象某值的差{cout _num - pt._num endl; //更好的区分对象}
private:int _num;
};int main()
{Test t1,t2;t1.subtract(t2);return 0;
} this指针特性 this指针的类型类类型* const即成员函数中不能给this指针赋值。只能在“成员函数”的内部使用。this指针本质上是“成员函数”的形参当对象调用成员函数时将对象地址作为实参传递给this形参。所以对象中不存储this指针。this指针是“成员函数”第一个隐含的指针形参一般情况由编译器通过ecx寄存器自动传递不需要用户传递this空指针 如果我们定义一个类指针指向空是否可以调用类函数 //示例代码
class Test
{
public:Test(int num 0) :_num(num){}void Fun1() //正常调用{cout Fun1被调用 endl;}void Fun2() //崩溃this空指针访问{cout Fun2被调用 _num _num endl;}private:int _num;
};int main()
{Test* t nullptr;t-Fun1();t-Fun2();return 0;
} 代码调试结果 这说明如果对象指针是空指针是可以正常调用函数的因为类的成员函数不是存在对象中如果函数中不涉及this指针的访问则程序可以正常运行否则此函数会崩溃 最后
类和对象(上)的知识介绍到这里就结束了我们区分了面向对象和面向过程编程的含义理解了什么是类类封装的意义等类的各种特性相信类和对象的学习会为大家打开一扇关于编程新的大门类的学习还不止于此后面还会继续为大家介绍类的成员函数
本次 C类和对象 - 上 就介绍到这里啦希望能够尽可能帮助到大家。
如果文章中有瑕疵还请各位大佬细心点评和留言我将立即修补错误谢谢 其他文章阅读推荐 C入门知识-CSDN博客 Linux基础指令-CSDN博客 Linux权限的基本知识-CSDN博客 欢迎读者多多浏览多多支持!