C++基础6:面向对象程序设计思想和类(上)

此专栏为移动机器人知识体系下的编程语言中的 C {\rm C} C++从入门到深入的专栏,参考书籍:《深入浅出 C {\rm C} C++》(马晓锐)和《从 C {\rm C} C C {\rm C} C++精通面向对象编程》(曾凡锋等)。



6.面向对象程序设计思想和类
6.1 程序设计思想
6.1.1 结构化程序设计思想
  • 结构化程序设计思想运用的是面向过程的结构化程序设计方法 ( s t r u c t u r e d p r o g r a m m i n g ) {\rm (structured\ programming)} (structured programming)

  • 结构化程序设计的基本思想:

    采用自顶向下、逐步求精的设计方法和单入口单出口的控制结构,一个复杂的问题可以划分为多个简单的问题组合;先将问题细化为由若干模块组成的层次结构,然后把每个模块的功能进一步细化,分解成一个个更小的子模块,直到分解为一个个程序的语句为止;

  • 结构化程序设计的优点:

    • 符合人分析问题的一般习惯和规律,容易理解、编写和维护;
    • 把一个问题逐步细化,从复杂到简单,逐个解决问题,分析问题是从整体到局部,解决问题是从局部到整体的过程;
  • 结构化程序设计的缺点:

    • 采用数据和操作分开的模式,一旦数据格式或结构发生变化,相应的操作函数就需要改变;
    • 无法对数据的安全性进行有效控制;
  • 结构化程序设计方法把解决问题的重点放在如何实现过程的细节方面,把数据和操作分开,以数据结构为核心,围绕功能实现或操作流程来设计程序;

  • 采用结构化程序设计方法设计出来的程序,基本形式是主模块与若干子模块的组合,即一个主程序加若干子程序,程序以函数为单位;

6.1.2 面向对象程序设计思想
  • 面向对象程序设计的基本思想:

    先将数据和对数据的操作方法集中存放在一个整体中,形成一个相互依存不可分割的整体,这个整体即为对相同类型的对象抽象出其共性而形成的类,类通过外部接口与外界发生联系,对象与对象之间通过消息进行通信;

  • 面向对象程序设计思想可以使程序模块间的关系变得简单,因为只有通过外部接口进行联系,且程序模块的相对独立性高,数据的安全性得到很好的保证;

  • 面向对象程序设计方法中,程序基本单位是类,类是 C {\rm C} C++封装的基本单位,把数据和函数封装在一起;

  • 对象概念:

    • 对象是世界中的一个独立的单位,对象都有自己的特征,如静态特征和动态特征;
    • 对象的静态特征可以用某种数据描述,动态特征为其所表现的行为或具有的功能;
    • 面向对象程序设计思想中,对象是描述世界事物的一个实体,是构成程序的一个基本单位;对象由一组属性(数据)和一组行为(函数)构成,属性用来描述对象的静态特征,行为用来描述对象的动态特征;
  • 类概念:

    • 抽象和分类是面向对象程序设计的两个原则,抽象是具体事物描述的一个概括,抽象与具体是相对应的,分类的依据原则是抽象;
    • 面向对象的类是具有相同属性和行为的一组对象的集合,能为属于该集合的全部对象提供抽象的描述(包括属性和行为);
    • 类和对象的关系是抽象与具体的关系,一个属于某个类的对象称为该类的一个实例;
  • 封装概念:

    • 封装指将对象的属性和行为组合成一个独立的单元,并尽可能隐藏对象的内部细节;
    • 封装的两个特点:
      • 将对象的全部属性和行为组合在一起,形成一个不可分割的独立单元(类);
      • 对这个独立单元进行信息隐藏,使外部无法轻易获得单元中的信息,从而达到信息保护的目的,外部只有通过单元的外部接口与其发生联系;
  • 继承概念:

    • 某一个类的对象拥有另一个类的全部属性和行为,可以将这个类声明为另一个类的继承;
    • 如果一个一般类具有更高抽象的特征,则其可被继承性就高,如果相对于这个一般类,某个特殊类具备其所有特征,可以直接继承这个特殊性简化开发任务;
  • 多态概念:

    • 多态指在一般类中定义的属性或行为在被类继承后可以具有不同的数据类型或表现出不同的行为,可以使一个属性或行为在一般类和其所继承类中具有不同的含义或实现;
6.2 类
  • 类的定义和基本结构

    • 类的定义:类是一种用户自定义的数据类型,定义一个类后,可以声明一个类的变量,这个变量称为类的对象或实例,这个声明类变量的过程称为类的实例化,类包含类头和类体两部分;

    • 类的基本结构:

      // 类的基本结构:
      class 类名			// 类头;
      {...				// 类体;
      };
      
    • 类头由关键字 c l a s s {\rm class} class和类的名称组成,类体是类的实现声明部分,由一对大括号 { } \{\} {}括起来,在最后需要加分号,命名类时加前缀" C {\rm C} C";

    • 类基本定义实例:

      // 定义一个手机类;
      class CMobilePhone{...
      };// 定义一个手机类并实例化;
      class CMobilePhone{...
      } myMobilePhone;// 定义一个书籍类;
      class CBook{...
      };// 定义一个书籍类并实例化;
      class CBook{...
      } myBook;
      
    • 在类的实现声明部分包含数据和函数,类中的数据称为数据成员,类中的函数称为成员函数,类的结构表示如下:

      class 类名
      {数据成员;数据成员;...;成员函数;成员函数;...;
      };
      
  • 数据成员

    • 类数据成员的声明语法格式:

      class CMobilePhone
      {string m_strPhoneName;					// 手机名称;string m_strPhoneType;					// 手机型号;float m_fLength,m_fWidth,m_fHeight;		// 手机长度、宽度、高度;
      };
      
    • 类数据成员的类型实例:

      enum MobilePhoneType {HUAWEI,XIAOMI,IPHONE};
      class CMobilePhone
      {string m_strPhoneName;					// 手机名称;MobilePhoneType m_ePhoneType;			// 手机型号;float m_fLength,m_fWidth,m_fHeight;		// 手机长度、宽度、高度;void (*pfApp)();						// 手机用户自安装应用程序指针;
      };
      
    • 除类中静态数据成员外,类的数据成员不能在类体内被显式初始化,类的数据成员通过类的构造函数进行初始化;

  • 成员函数

    • 成员函数用来操作数据成员的,成员函数的原型在类体中被声明,基本形式如下:

      class 类名
      {访问控制关键字 返回值类型 成员函数名(参数列表);		// 函数原型声明;
      };
      
    • 在类体中声明函数原型后,需要实现函数,一般在类体外进行成员函数的实现,形式如下:

      返回值类型 类名::成员函数名()
      {函数体;
      }
      
    • 类名后" : : :: ::"为域解析操作符,用于在程序中来访问类域中声明的成员,成员函数必须在类中定义原型后再实现;

    • 如果成员函数实现简单,可以直接在类中实现,在类中称为内联成员函数,直接在成员函数声明处实现函数称为隐式声明,将 i n l i n e {\rm inline} inline关键字放在函数声明处或放在类外的实现部分,称为显式声明,实例如下:

      // 需求:定义一个手机类,包括一个显示手机名、型号、尺寸的成员函数;
      class CMobilePhone
      {void SetPhoneName(string);void ShowPhoneName();void ShowPhoneType(){			// 隐式声明格式;cout << m_strPhoneType;};								// 相当于一个语句结束加分号;void ShowPhoneSize();/* 参数说明:* m_strPhoneName:手机名;* m_strPhoneType:手机型号;* m_fLength,m_fWidth,m_fHeight:手机尺寸;*/string m_strPhoneName;string m_strPhoneType;float m_fLength,m_fWidth,m_fHeight;
      };// 标准的成员函数声明和定义格式;
      void CMobilePhone::ShowPhoneName()
      {cout << "Name of Phone:" << m_strPhoneName << endl;
      }// inline关键字显式声明格式;
      inline void CMobilePhone::ShowPhoneSize()
      {cout << "The phone size is:" << m_fLenght << "x" << m_fWidth << "x" << m_fHeight << endl;
      }// inline关键字显式声明格式;
      inline void CMobilePhone::SetPhoneName(string strPhoneName)
      {m_strPhoneName = strPhoneName;
      }
      
      // 需求:定义一个学生信息类,包括显示学生的学号、身高、体重、年龄的成员函数;
      class CStudentInfo
      {string m_strStudentID;int m_intStudentHeight;int m_intStudentWeight;int m_intStudentAge;void ShowStudentID(){cout << "StudentID is:" << m_strStudentID << endl;};void ShowStudentHeight();void ShowStudentWeight();void ShowStudentAge();
      };void CStudentInfo::ShowStudentHeight()
      {cout << "Student height is:" << m_intStudentHeight << endl;
      }void CStudentInfo::ShowStudentWeight()
      {cout << "Student weight is:" << m_intStudentWeight << endl;
      }inline void CStudentInfo::ShowStudentAge()
      {cout << "Student age is:" << m_intStudentAge << endl;
      }
      
  • 类成员的访问控制:对类成员访问权限的控制是通过成员的访问控制属性实现,类的访问控制属性有三种:

    • 公有类型 ( p u b l i c ) ({\rm public}) (public):公有类型成员用关键字 p u b l i c {\rm public} public声明,公有类型的成员可以被类内部成员访问,也可以被类外部成员访问,对于外部成员来说,想访问类的成员,必须通过类的公有类型成员来访问,公有类型成员是外部访问类的唯一接口;
    • 私有类型 ( p r i v a t e ) ({\rm private}) (private):私有类型成员用关键字 p r i v a t e {\rm private} private声明,私有类型的成员只允许本类内部的成员函数访问,类外部的任何访问都被拒绝,这样可对类中的私有成员进行了有效的隐藏和保护;
    • 保护类型 ( p r o t e c t e d ) ({\rm protected}) (protected):保护类型成员用关键字 p r o t e c t e d {\rm protected} protected声明,保护类型和私有类型类似,区别于类继承过程中对新类的影响不同;
  • 类成员的访问控制属性声明语法格式实例:

    // 格式1:分开声明;class CMobilePhone
    {private string m_strPhoneName;private string m_strPhoneType;public void ShowPhoneName();public void ShowPhoneType();
    };// 格式2:相同控制属性的成员合并定义;
    class CMobilePhone
    {private:string m_strPhoneName;string m_strPhoneType;public:void ShowPhoneName();void SHowPhoneType();
    }
    
    // 需求:定义一个手机类,实现显示手机名、型号、重量的功能;
    class CMobilePhone
    {private:string m_strPhoneName;		// 手机名称;string m_strPhoneType;		// 手机型号;float m_fPhoneWeight;		// 手机重量;public:void ShowPhoneName();void ShowPhoneType(){cout << "Type of Phone is:" << m_strPhoneType << endl;};void ShowPhoneWeight();
    };void CMobilePhone::ShowPhoneName()
    {cout << "Name of phone is:" << m_strPhoneName << endl;
    }void CMobilePhone::ShowPhoneWeight()
    {cout << "Weight of Phone is:" << m_fPhoneWeight << endl;
    }
    
  • 类的实例和类成员访问

    • 类描述了一类事物的共同属性和行为,当把抽象的描述变成一个具体的事物时,此时成为了类的一个实例或称为对象 ( i n s t a n c e o r o b j e c t ) ({\rm instance\ or\ object}) (instance or object)

    • 简单理解:类的定义类似一个产品的模具,通过这个模具可以生产出多个产品,这些产品即为实例;

    • 类是一种自定义的数据类型,类的实例也就是这个类的一个变量,声明实例的语法格式:

      // 1.一般的声明实例格式:
      类名 实例名1,实例名2,...;// 2.声明类的一个实例指针格式:
      类名 *实例指针名1,*实例指针名2,...;// 3.用实例地址或用new开辟一个新的实例来对实例指针赋值;
      CMobilePhone *pCMP_A1200;
      pCMP_A1200 = new pCMP_A1200();// 4.声明实例数组:
      CMobilePhone arrCMP_A1200[5];		// 实例数组;
      CMobilePhone *parrCMP_A1200[5];		// 实例指针数组;
      
    • 定义一个类时,系统不分配存储空间给这个类,因为这个类是虚拟的描述,不是真正的实体;当声明一个类的实例后,系统分配存储空间,此时系统需要分配空间用于存储类中的数据成员;

    • 声明多个实例时,操作任何一个实例都不会对其他实例造成影响,他们有各自的类数据成员的副本;

    • 声明类的实例后,就可以访问类的公有成员了,当声明的是类的实例(非实例指针)时,通过点 ( . ) (.) (.)访问,当声明的是一个实例指针时,在指定了对象后,用成员访问操作符箭头(->)访问,格式如下:

      // 1.一般类实例
      实例.类成员;// 举例
      CMobilePhone HUAWEI;
      HUAWEI.ShowPhoneName();
      HUAWEI.ShowPhoneType();// 2.实例指针
      实例指针->类成员;// 举例
      CMobilePhone HUAWEI;
      CMobilePhone *pHUAWEI = &HUAWEI;
      pHUAWEI->ShowPhoneName();
      pHUAWEI->ShowPhoneType();// 3.对于实例数组或实例指针数组,访问其成员函数需要加上实例数组的下标;
      CMobilePhone arrHUAWEI[5];
      arrHUAWEI[1].ShowPhoneName();CMobilePhone *parrHUAWEI[5];
      parrHUAWEI[0] = new CMobilePhone();
      parrHUAWEI[0]->ShowPhoneName();
      
  • 手机类实战 ( M o b i l e P h o n e ) ({\rm MobilePhone}) (MobilePhone)项目:

    • 项目需求:编写一个手机类,实现设置和显示手机名、型号、尺寸的功能,并声明一个针对 H U A W E I M a t e 30 {\rm HUAWEI\ Mate\ 30} HUAWEI Mate 30型号的实例,实现设置和显示手机名、型号、尺寸的功能。

    • 程序结构:

      • 程序主文件: m a i n . c p p {\rm main.cpp} main.cpp
      • 手机类定义头文件: M o b i l e P h o n e . h {\rm MobilePhone.h} MobilePhone.h
      • 手机类实现文件: M o b i l e P h o n e . c p p {\rm MobilePhone.cpp} MobilePhone.cpp
    • 手机类定义头文件 ( M o b i l e P h o n e . h ) ({\rm MobilePhone.h}) (MobilePhone.h)

      /*** 作者:罗思维* 时间:2024/03/06* 描述:手机类定义头文件。*/
      #include <string>
      #include <iostream>using namespace std;class CMobilePhone {private:string m_strPhoneName;					// 手机名称;string m_strPhoneType;					// 手机型号;float m_fLength, m_fWidth, m_fHeight;	// 手机尺寸;public:void SetPhoneName();void SetPhoneType();void SetPhoneSize();void ShowPhoneName();void ShowPhoneType();void ShowPhoneSize();
      };
      
    • 手机类实现文件 ( M o b i l e P h o n e . c p p ) ({\rm MobilePhone.cpp}) (MobilePhone.cpp)

      /*** 作者:罗思维* 时间:2024/03/06* 描述:手机类实现文件。*/
      #include "MobilePhone.h"void CMobilePhone::SetPhoneName() {cout << "请输入手机名字:";cin >> m_strPhoneName;
      }void CMobilePhone::SetPhoneType() {cout << "请输入手机型号:";cin >> m_strPhoneType;
      }void CMobilePhone::SetPhoneSize() {cout << "请输入手机尺寸(长、宽、高):";cin >> m_fLength >> m_fWidth >> m_fHeight;
      }void CMobilePhone::ShowPhoneName() {cout << "Name of mobile phone:" << m_strPhoneName << endl;
      }void CMobilePhone::ShowPhoneType() {cout << "Type of mobile phone:" << m_strPhoneType << endl;
      }void CMobilePhone::ShowPhoneSize() {cout << "Size of mobile phone:" << m_fLength<< "x" << m_fWidth << "x" << m_fHeight << endl;
      }
      
    • 程序主文件 ( m a i n . c p p ) ({\rm main.cpp}) (main.cpp)

      /*** 作者:罗思维* 时间:2024/03/06* 描述:手机类实现主文件。*/#include "MobilePhone.h"int main() {CMobilePhone HUAWEI_MATE30;			// 声明手机对象; HUAWEI_MATE30.SetPhoneName();HUAWEI_MATE30.SetPhoneType();HUAWEI_MATE30.SetPhoneSize();cout << "如下是HUAWEI MATE30的相关信息:" << endl;HUAWEI_MATE30.ShowPhoneName();HUAWEI_MATE30.ShowPhoneType();HUAWEI_MATE30.ShowPhoneSize();return 0;
      }
      
  • 学生类实战 ( S t u d e n t ) ({\rm Student}) (Student)项目:

    • 项目需求:编写一个学生类,实现设置和显示学生姓名、学生班级、学生身高、学生体重的功能,声明一个学生的实例,实现设置和显示学生姓名、学生班级、学生身高、学生体重的功能。

    • 程序结构:

      • 程序主文件: m a i n . c p p {\rm main.cpp} main.cpp
      • 学生类定义头文件: S t u d e n t . h {\rm Student.h} Student.h
      • 学生类实现文件: S t u d e n t . c p p {\rm Student.cpp} Student.cpp
    • 学生类定义头文件 ( S t u d e n t . h ) ({\rm Student.h}) (Student.h)

      /*** 作者:罗思维* 时间:2024/03/06* 描述:学生类实现头文件。*/
      #include <string>
      #include <iostream>using namespace std;class CStudent {private:string m_strStudentName;		// 学生姓名; string m_strStudentClass;		// 学生班级; float m_fStudentHeight;			// 学生身高; float m_fStudentWeight;			// 学生体重; public:void SetStudentName();void SetStudentClass();void SetStudentHeight();void SetStudentWeight();void ShowStudentName();void ShowStudentClass();void ShowStudentHeight();void ShowStudentWeight();
      };
      
    • 学生类实现文件 ( S t u d e n t . c p p ) ({\rm Student.cpp}) (Student.cpp)

      /*** 作者:罗思维* 时间:2024/03/06* 描述:学生类实现文件。*/#include "Student.h"void CStudent::SetStudentName() {cout << "请输入学生姓名:";cin >> m_strStudentName;
      }void CStudent::SetStudentClass() {cout << "请输入学生班级:";cin >> m_strStudentClass;
      }void CStudent::SetStudentHeight() {cout << "请输入学生身高:";cin >> m_fStudentHeight;
      }void CStudent::SetStudentWeight() {cout << "请输入学生体重:";cin >> m_fStudentWeight;
      }void CStudent::ShowStudentName() {cout << "学生姓名为:" << m_strStudentName << endl;
      }void CStudent::ShowStudentClass() {cout << "学生班级为:" << m_strStudentClass << endl;
      }void CStudent::ShowStudentHeight() {cout << "学生身高为:" << m_fStudentHeight << "cm" << endl;
      }void CStudent::ShowStudentWeight() {cout << "学生体重为:" << m_fStudentWeight << "Kg" << endl;
      }
      
    • 学生类主文件 ( m a i n . c p p ) ({\rm main.cpp}) (main.cpp)

      /*** 作者:罗思维* 时间:2024/03/06* 描述:手机类实现主文件。*/
      #include "Student.h"int main() {CStudent student;student.SetStudentName();student.SetStudentClass();student.SetStudentHeight();student.SetStudentWeight();cout << endl;cout << "学生的个人基本信息为:" << endl << endl;student.ShowStudentName();student.ShowStudentClass();student.ShowStudentHeight();student.ShowStudentWeight();return 0;
      }
      
  • 类的作用域和对象的生存周期

    • 一个类是一个整体,类中所有的成员都位于类的作用域内,类的作用域指的是类定义和成员函数定义的范围,在类作用域中,类的成员函数可以无限制地访问自身类中的数据成员;

    • 对于类作用域外的其他类的数据成员和成员函数,访问类作用域内的成员受到限制,即封装的思想,把一个类的数据和行为封装起来,使得类的外部对该类的数据访问受到限制;

    • 类的成员函数内部出现与类成员相同的标识符,此时类中这个相同的标识符不再具有对这个成员函数的作用域,如:对于类 C M o b i l e P h o n e {\rm CMobilePhone} CMobilePhone,如果成员函数 S e t P h o n e N a m e {\rm SetPhoneName} SetPhoneName中出现了与数据成员 m _ s t r P h o n e T y p e {\rm m\_strPhoneType} m_strPhoneType相同名称的变量,则 m _ s t r P h o n e T y p e {\rm m\_strPhoneType} m_strPhoneType不在成员函数的作用域内;

    • 类作用域实例:

      void CMobilePhone::SetPhoneName()
      {/* 此成员函数中的局部变量m_strPhoneType与类中的数据成员CMobilePhone::m_strPhoneType* 具有相同的名称,则CMobilePhone::m_strPhoneType在成员函数中被屏蔽,不可见;*/string m_strPhoneType;cin >> m_strPhoneType;		// 此时CMobilePhone::m_strPhoneType被隐藏;if(m_strPhoneType == "MATE30"){m_strPhoneName = "HUAWEI";}
      }
      
    • 利用点 ( . ) (.) (.)、箭头( − - >)、作用域运算符 ( : : ) (::) (::)访问类成员时,类成员具有类的作用域;

  • t h i s {\rm this} this指针

    • t h i s {\rm this} this指针是隐含在类中每一个成员函数中的特殊指针,用于指向正在被成员函数操作的对象;

    • t h i s {\rm this} this指针工作原理:当通过一个类的实例调用成员函数时,系统会将该实例的地址赋予 t h i s {\rm this} this指针,再调用成员函数,因此, ∗ t h i s *{\rm this} this代表此实例;

    • 程序中一般不直接使用 t h i s {\rm this} this来访问类的成员,除非是在变量的作用域中发生了冲突;

    • t h i s {\rm this} this指针实例:

      void CMobilePhone::SetPhoneName()
      {string m_strPhoneType;						// CMobilePhone::m_strPhoneType被隐藏;cin >> m_strPhoneType;if(m_strPhoneType == "MATE30"){m_strPhoneName = "HUAWEI";}this->m_strPhoneType = m_strPhoneType;		// 利用this指针访问类中的数据成员;
      }
      
  • 静态成员

    • 类的静态数据成员和静态成员函数统称为类的静态成员, C {\rm C} C++是通过静态成员来实现类的属性和行为的;

    • 在一个类声明的多个实例中,每一个实例都维持着一份该类所有数据成员的副本;静态数据成员是一种特殊的数据成员,在类的所有实例中只有一个副本,由所有实例来共同维护和使用,达到数据在所有实例中的共享;

    • 静态数据成员采用 s t a t i c {\rm static} static关键字声明,形式如下:

      static 数据类型 数据成员名;
      
    • 静态数据成员实例 ( S m s ) ({\rm Sms}) (Sms)项目:

      • 项目需求:编写一个手机短信息类,要求能够实现统计短信息总数的功能。

      • 程序主文件: m a i n . c p p {\rm main.cpp} main.cpp

      • 短信息类定义的头文件: C S m s . h {\rm CSms.h} CSms.h

      • 短信息类实现文件: C S m s . c p p {\rm CSms.cpp} CSms.cpp

      • 短信息类定义头文件代码 ( C S m s . h ) ({\rm CSms.h}) (CSms.h)

        /*** 作者:罗思维* 时间:2024/03/07* 描述:手机短信息类定义头文件。*/
        #include <iostream>
        #include <string>using namespace std;class CSms {private:/* 参数说明:* m_strSmsFrom:	信息来源;* m_strSmsTo:		信息发送对象;* m_strSmsTitle:	信息头部;* m_strSmsBody:	信息内容;* sm_nSmsTotal:	信息总数;*/string m_strSmsFrom;string m_strSmsTo;string m_strSmsTitle;string m_strSmsBody;static int sm_nSmsTotal;public:void ShowSmsTotal();void SetSmsTotal();
        };
        
      • 短信息类实现文件代码 ( C S m s . c p p ) ({\rm CSms.cpp}) (CSms.cpp)

        /*** 作者:罗思维* 时间:2024/03/07* 描述:手机短信息类实现文件。*/#include "CSms.h"void CSms::SetSmsTotal() {sm_nSmsTotal++;
        }void CSms::ShowSmsTotal() {cout << "手机短信息总数:" << sm_nSmsTotal << endl;
        }
        
      • 程序主文件代码 ( m a i n . c p p ) ({\rm main.cpp}) (main.cpp)

        /*** 作者:罗思维* 时间:2024/03/07* 描述:手机短信息总数统计主文件。*/#include "CSms.h"int CSms::sm_nSmsTotal = 0;		// 类静态数据成员的定义性说明和初始化;int main() {CSms sms1, sms2;sms1.ShowSmsTotal();sms2.ShowSmsTotal();sms1.SetSmsTotal();		// 设定对象sms1中的短信息数量;sms1.ShowSmsTotal();sms2.ShowSmsTotal();sms2.SetSmsTotal();		// 设定对象sms2中的短信息数量;sms1.ShowSmsTotal();sms2.ShowSmsTotal();return 0;
        }
        
    • 静态数据成员具有静态生存期,不属于任何一个实例,只能通过类名访问,格式如下:

      类名::静态成员数据名
      
    • 类定义中,所声明的静态数据成员只是对它的引用性说明,必须在文件作用域内对其进行定义性说明和初始化,语法格式如下:

      数据类型 类名::静态成员数据名 = 初始值;// 举例
      int CSms::sm_nSmsTotal = 0;
      
  • 静态成员函数

    • 普通成员函数必须在声明实例后才能被访问,静态成员函数不需要类的实例就可以被直接访问;

    • 静态成员函数采用 s t a t i c {\rm static} static关键字来声明,语法格式如下:

      static 返回值类型 成员函数名(参数表);
      
    • 静态成员函数具有静态生存期,不属于任何一个实例,只能通过类名来访问,语法格式如下:

      类名::成员函数名
      
    • 静态成员函数实例 ( C s m 2 ) ({\rm Csm2}) (Csm2)项目:

      • 项目需求:编写一个手机短信息类,利用静态成员函数取得短信息总数。

      • 程序主文件: m a i n . c p p {\rm main.cpp} main.cpp

      • 短信息类的定义头文件: C S m s . h {\rm CSms.h} CSms.h

      • 短信息类实现文件: C S m s . c p p {\rm CSms.cpp} CSms.cpp

      • 短信息类定义头文件代码 ( C S m s . h ) ({\rm CSms.h}) (CSms.h)

        /*** 作者:罗思维* 时间:2024/03/07* 描述:手机短信息类定义头文件。*/
        #include <iostream>
        #include <string>using namespace std;class CSms {private:/* 参数说明:* m_strSmsFrom:	信息来源;* m_strSmsTo:		信息发送对象;* m_strSmsTitle:	信息头部;* m_strSmsBody:	信息内容;* sm_nSmsTotal:	信息总数;*/string m_strSmsFrom;string m_strSmsTo;string m_strSmsTitle;string m_strSmsBody;static int sm_nSmsTotal;public:static void ShowSmsTotal();void SetSmsTotal();
        };
        
      • 短信息类实现文件代码 ( C S m s . c p p ) ({\rm CSms.cpp}) (CSms.cpp)

        /*** 作者:罗思维* 时间:2024/03/07* 描述:手机短信息类实现文件。*/#include "CSms.h"void CSms::SetSmsTotal() {sm_nSmsTotal++;
        }void CSms::ShowSmsTotal() {cout << "手机短信息总数:" << sm_nSmsTotal << endl;
        }
        
      • 程序主文件 ( m a i n . c p p ) ({\rm main.cpp}) (main.cpp)

        /*** 作者:罗思维* 时间:2024/03/07* 描述:手机短信息总数统计主文件。*/
        #include "CSms.h"int CSms::sm_nSmsTotal = 0;		// 类静态数据成员的定义性说明和初始化; int main() {CSms sms;CSms::ShowSmsTotal();		// 调用静态成员函数输出短信息总数; sms.SetSmsTotal();			// 对短信息数进行设定; CSms::ShowSmsTotal();		 sms.ShowSmsTotal();return 0;
        }
        
    • 类的静态成员函数可以直接访问该类的静态数据成员和静态函数成员,不能直接访问非静态数据成员和非静态成员函数,非静态成员的访问需要通过实例进行;

    • 如果静态成员函数需要访问类的非静态成员,则需要通过参数取得实例名,再通过实例名进行访问;

  • 类的静态成员访问实例:

    class class_name
    {private:int nVar;static int snVar;public:static void Func(class_name a);static void Func2();void Func3();
    };void class_name::Func(class_name a)
    {cout << nVar;		// 错误,直接引用类的非静态数据成员无效;Func3();			// 错误,直接引用类的非静态成员函数无效;cout << a.nVar;		// 正确,通过实例访问类的非静态数据成员;a.Func3();			// 正确,通过实例访问类的非静态成员函数;cout << snVar;		// 正确,通过实例访问类的静态数据成员;Func2();			// 正确,通过实例访问类的静态成员函数;
    }
    
  • 常成员

    • 利用 c o n s t {\rm const} const修饰类的数据成员时,该数据成员为常数据成员,当修饰类的函数成员时,该数据为常函数成员;

    • 常数据成员通过 c o n s t {\rm const} const关键字来声明,语法格式如下:

      const 数据类型 常数据成员名;
      
    • 在类中定义的常数据成员不能被任何一个函数改变,对常数据的初始化只能在类的构造函数中进行,初始化的方式是通过初始化列表;

  • 常成员实例 ( S m s 2 ) ({\rm Sms2}) (Sms2)项目:

    • 项目需求:编写一个手机短信息类,定义一个用于表示信息最大长度的常数据成员。

    • 程序主文件: m a i n . c p p {\rm main.cpp} main.cpp

    • 短信息类定义头文件: C S m s . h {\rm CSms.h} CSms.h

    • 短信息类实现文件: C S m s . c p p {\rm CSms.cpp} CSms.cpp

    • 短信息类定义头文件代码 ( C S m s . h ) ({\rm CSms.h}) (CSms.h)

      /*** 作者:罗思维* 时间:2024/03/08* 描述:手机短信息类定义头文件。*/
      #include <iostream>
      #include <string>using namespace std;class CSms {private:string m_strSmsFrom;		// 信息来源; string m_strSmsTo;			// 信息发送对象; string m_strSmsTitle;		// 信息头部; string m_strSmsBody;		// 信息内容; static int sm_nSmsTotal;	// 信息总数; const int cMAX_MSG_LEN;		// 信息的最大长度; public:CSms(int);					// 构造函数; void ShowMaxMsgLen();static void ShowSmsTotal();
      };
      
    • 短信息类实现文件代码 ( C S m s . c p p ) ({\rm CSms.cpp}) (CSms.cpp)

      /*** 作者:罗思维* 时间:2024/03/08* 描述:手机短信息类实现文件。*/#include "CSms.h"CSms::CSms(int nMaxMsgLen): cMAX_MSG_LEN(nMaxMsgLen) {
      }void CSms::ShowMaxMsgLen() {cout << "cMAX_MSG_LEN:" << cMAX_MSG_LEN << endl;
      }
      
    • 程序主文件代码 ( m a i n . c p p ) ({\rm main.cpp}) (main.cpp)

      /*** 作者:罗思维* 时间:2024/03/08* 描述:手机短信息主文件。*/
      #include "CSms.h"int main() {CSms sms(140);sms.ShowMaxMsgLen();return 0;
      }
      
  • 常成员函数

    • c o n s t {\rm const} const关键字定义的函数为常成员函数,语法格式如下:

      数据类型 函数名(参数表) const;// 举例
      void ShowPhoneName() const;
      
    • 常成员函数的主要作用是禁止在函数体内更新实例的数据成员,在函数体内,一方面不能改变数据成员的值,另一方面不能调用该类中能改变数据成员的成员函数,即不能调用该类中其他非常成员函数;

  • 常成员函数 ( M o b i l e P h o n e ) ({\rm MobilePhone}) (MobilePhone)项目:

    • 项目需求:编写一个手机类,定义用于显示手机基本信息的常成员函数。

    • 程序结构:

      • 程序主文件: m a i n . c p p {\rm main.cpp} main.cpp
      • 手机类定义头文件: M o b i l e P h o n e . h {\rm MobilePhone.h} MobilePhone.h
      • 手机类实现文件: M o b i l e P h o n e . c p p {\rm MobilePhone.cpp} MobilePhone.cpp
    • 程序主文件代码 ( m a i n . c p p ) ({\rm main.cpp}) (main.cpp)

      /*** 作者:罗思维* 时间:2024/03/11* 描述:手机相关信息主文件。*/
      #include "MobilePhone.h"int main() {CMobilePhone HUAWEI;HUAWEI.SetPhoneName();HUAWEI.SetPhoneType();HUAWEI.SetPhoneSize();cout << "HUAWEI Phone Information:" << endl;HUAWEI.ShowPhoneName();HUAWEI.ShowPhoneType();HUAWEI.ShowPhoneSize();return 0;
      }
      
    • 手机类定义头文件代码 ( M o b i l e P h o n e . h ) ({\rm MobilePhone.h}) (MobilePhone.h)

      /*** 作者:罗思维* 时间:2024/03/11* 描述:手机相关信息定义头文件。*/
      #include <string>
      #include <iostream>using namespace std;class CMobilePhone{private:string m_strPhoneName;string m_strPhoneType;float m_fLength,m_fWidth,m_fHeight;public:void SetPhoneName();void SetPhoneType();void SetPhoneSize();void ShowPhoneName() const;void ShowPhoneType() const;void ShowPhoneSize() const;
      };
      
    • 手机类实现文件代码 ( M o b i l e P h o n e . c p p ) ({\rm MobilePhone.cpp}) (MobilePhone.cpp)

      /*** 作者:罗思维* 时间:2024/03/11* 描述:手机相关信息实现文件。*/
      #include "MobilePhone.h"void CMobilePhone::SetPhoneName() {cout << "请输入手机名称:";cin >> m_strPhoneName;
      }void CMobilePhone::SetPhoneType() {cout << "请输入手机类型:";cin >> m_strPhoneType;
      }void CMobilePhone::SetPhoneSize() {cout << "请输入手机尺寸:";cin >> m_fLength >> m_fWidth >> m_fHeight;
      }void CMobilePhone::ShowPhoneName() const {cout << "m_strPhoneName:" << m_strPhoneName << endl;
      }void CMobilePhone::ShowPhoneType() const {cout << "m_strPhoneType:" << m_strPhoneType << endl;
      }void CMobilePhone::ShowPhoneSize() const {cout << "m_strPhoneSize:" << m_fLength << "x" << m_fWidth << "x" << m_fHeight << endl;
      }
      

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/753863.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

春招第一面-京东

宝子们&#xff0c;卷起来吧&#xff01; 1、自我介绍 2、实习项目 3、实习项目分库分表怎么做的&#xff1f; 4、分布式主键用的是什么&#xff1f;雪花ID是怎么样的&#xff0c;有什么问题&#xff1f; 5、实习业务具体是干嘛 6、你们这个业务为啥不用es&#xff0c;如…

vscode中自动生成python的UML类图的插件

需求&#xff1a; 阅读一些源码时&#xff0c;想直观的看一下它的UML类关系图。 搜索发现已有相关的软件可以实现这个功能。 Linux系统&#xff1a; 安装pylint pip3 install pylint 使用pyreverse命令 pyreverse -ASmy -o png test.py 生成名为classes.png的UML类图 参考…

苍穹外卖-day08:导入地址簿功能代码(单表crud)、用户下单(业务逻辑)、订单支付(业务逻辑,cpolar软件)

苍穹外卖-day08 课程内容 导入地址簿功能代码用户下单订单支付 功能实现&#xff1a;用户下单、订单支付 用户下单效果图&#xff1a; 订单支付效果图&#xff1a; 1. 导入地址簿功能代码&#xff08;单表crud&#xff09; 1.1 需求分析和设计 1.1.1 产品原型&#xff08…

苍穹外卖-day04:项目实战-套餐管理(新增套餐,分页查询套餐,删除套餐,修改套餐,起售停售套餐)业务类似于菜品模块

苍穹外卖-day04 课程内容 新增套餐套餐分页查询删除套餐修改套餐起售停售套餐 要求&#xff1a; 根据产品原型进行需求分析&#xff0c;分析出业务规则设计接口梳理表之间的关系&#xff08;分类表、菜品表、套餐表、口味表、套餐菜品关系表&#xff09;根据接口设计进行代…

rocky9 编写一键安装mysql 的sh脚本

基本操作步骤 1、虚拟机最小化安装rocky9系统&#xff0c;安装后克隆一个系统&#xff1b;1个用来获取下载的rpm包&#xff0c;一个用来编写sh 测试脚本&#xff1b; 2、修改虚拟机的 yum配置文件&#xff0c;获取获取rpm程序 &#xff1a;启用缓存&#xff0c;并修改yum下载…

比特币,区块链及相关概念简介(二)

目录 什么是挖矿挖矿是否代表资源浪费为什么挖矿能维持比特币网络安全性&#xff1f;是怎么做到的呢&#xff1f;该系列文章链接 以下内容结合了chatgpt 3.5以及网络文章。 用于学习记录。 简介&#xff1a; 介绍了什么是挖矿&#xff0c;挖矿是否代表资源浪费&#xff0c;挖矿…

四个按键控制数码管分别显示6,8 ,A,F

#include<reg52.h> typedef unsigned int u16; //重新定义系统默认数据类型 typedef unsigned char u8; #define SMG_A_DP_PORT P0 //使用宏定义定义P0端口&#xff0c;数码管段码口 …

【数据结构与算法】:非递归实现快速排序、归并排序

&#x1f525;个人主页&#xff1a; Quitecoder &#x1f525;专栏&#xff1a;数据结构与算法 上篇文章我们详细讲解了递归版本的快速排序&#xff0c;本篇我们来探究非递归实现快速排序和归并排序 目录 1.非递归实现快速排序1.1 提取单趟排序1.2 用栈实现的具体思路1.3 代码…

Linux:git的基础操作

git的下载 版本控制系统一般分为两种&#xff0c;集中式版本控制系统&#xff0c;分布式版本控制系统 什么是集中式版本控制系统&#xff1a;版本库集中存放在中央服务器&#xff0c;工作时候使用自己的电脑&#xff0c;当工作时候在中央服务器上拉取最新版本的代码&#xff0c…

U盘变身“本地磁盘”?数据恢复与防范策略大揭秘

一、突发状况&#xff1a;U盘秒变“本地磁盘” 在日常工作生活中&#xff0c;U盘凭借其便携性和大容量&#xff0c;成为我们存储和传输数据的重要工具。然而&#xff0c;有时我们会遇到这样一个棘手的问题&#xff1a;原本应显示为可移动磁盘的U盘&#xff0c;在插入电脑后却突…

ModuleNotFoundError: No module named,(python跨文件导包)

方法一&#xff1a;在文件中开头加入&#xff1a; import os import sys REPO os.path.dirname(os.path.dirname(os.path.realpath(__file__))) sys.path.append(REPO) 方法二&#xff1a;直接添加环境变量&#xff08;比较好用&#xff09; # 添加环境变量export PYTHONPAT…

Nginx 的安装、启动和关闭

文章目录 一、背景说明二、Nginx 的安装2.1、依赖的安装2.2、Nginx 安装2.3、验证安装 三、启动 Nginx3.1、普通启动3.2、如何判断nginx已启动3.3、通过配置启动3.4、设置开机启动 四、关闭 Nginx4.1、优雅地关闭4.2、快速关闭4.3、只关闭主进程4.4、使用nginx关闭服务 五、重启…

R语言:microeco:一个用于微生物群落生态学数据挖掘的R包:第七:trans_network class

# 网络是研究微生物生态共现模式的常用方法。在这一部分中&#xff0c;我们描述了trans_network类的所有核心内容。 # 网络构建方法可分为基于关联的和非基于关联的两种。有几种方法可以用来计算相关性和显著性。 #我们首先介绍了基于关联的网络。trans_network中的cal_cor参数…

编曲学习:如何编写钢琴织体 Cubase12逻辑预置 需要弄明白的问题

钢琴织体是指演奏形式、方式,同一个和弦进行可以用很多种不同的演奏方法。常用织体有分解和弦,柱式和弦,琶音织体,混合织体。 在编写钢琴织体前,先定好歌曲的调。 Cubase小技巧:把钢琴轨道向上拖动打和弦轨道,就可以显示和弦!如果你有一些参考工程,不知道用了哪些和…

yum安装mysql及数据库补全功能

centos7上面没有mysql&#xff0c;它的数据库名字叫做mariadb [rootlocalhost ~]#yum install mariadb-server -y [rootlocalhost ~]#systemctl start mariadb.service [rootlocalhost ~]#systemctl stop firewalld [rootlocalhost ~]#setenforce 0 [rootlocalhost ~]#ss -na…

kerberos验证协议安装配置使用

一、kerberos是什么 Kerberos 是一个网络身份验证协议&#xff0c;用于在计算机网络中进行身份验证和授权。它提供了一种安全的方式&#xff0c;允许用户在不安全的网络上进行身份验证&#xff0c;并获取访问网络资源的权限。 二、安装配置kerberos服务端 1、安装kerberos #检…

微信小程序 nodejs+vue+uninapp学生在线选课作业管理系统

基于微信小程序的班级作业管理助手使用的是MySQL数据库&#xff0c;nodejs语言和IDEA以及微信开发者工具作为开发工具&#xff0c;这些技术和工具我在日常的作业中都经常的使用&#xff0c;并且因为对编程感兴趣&#xff0c;在闲暇时间也进行的进行编程的提高&#xff0c;所以在…

计算机二级(Python)真题讲解每日一题:《十字叉》

描述‪‬‪‬‪‬‪‬‪‬‮‬‪‬‫‬‪‬‪‬‪‬‪‬‪‬‮‬‪‬‮‬‪‬‪‬‪‬‪‬‪‬‮‬‪‬‭‬‪‬‪‬‪‬‪‬‪‬‮‬‫‬‮‬‪‬‪‬‪‬‪‬‪‬‮‬‭‬‫‬‪‬‪‬‪‬‪‬‪‬‮‬‫‬‪‬‪‬‪‬‪‬‪‬‪‬‮‬‪‬‮‬ ‪‬‪‬‪‬‪‬‪‬‮‬‪…

二、python基础

一、关键字&#xff08;保留字&#xff09; 指在python中赋予特定意义的一类单词&#xff0c;不能将关键字作为函数、变量、类、模块的名称 import keyword#利用内存模块keyword print(keyword.kwlist)#输出所有关键 print(len(keyword.kwlist))#利用内置函数len()输出关键字的…

Python笔记四之协程

本文首发于公众号&#xff1a;Hunter后端 原文链接&#xff1a;Python笔记四之协程 协程是一种运行在单线程下的并发编程模型&#xff0c;它的特点是能够在一个线程内实现多个任务的并发操作&#xff0c;通过在执行任务时主动让出执行权&#xff0c;让其他任务继续执行&#xf…