C++ :面向对象程序设计(代码记录)

news/2024/9/23 11:43:12/

C++ :面向对象程序设计(代码记录)

  • 引言
    • 1. 类的封装
    • 2. 类的继承
    • 3. 类的多态
    • 4. 方法重载
    • 5. 抽象类
    • 6. 接口类
    • 7. 异常处理

引言

  • 本期内容为代码分享,记录学习C++面向程序设计的代码思路,以防止日后忘记,增加一点个人理解和数据上的文本,方便理解。

  • 为了方便阅读,下面的所有代码都只有一个目的:一天之中有86400秒,输入一个0到86400之间的数字,计算出其对应的小时、分钟、秒值。

  • 因为是代码分享,所以不会有介绍C++相关概念的内容,需要有一定的C++基础,但编程思想上是通用的。

  • 本人为C++初学者(以前学过一点,不过没坚持下来,忘记了),如果有错误的地方,还请指正!!!

1. 类的封装

  1. 面向对象和面向过程

面向过程是一种以过程为中心的编程思想,以什么正在发生为目标进行编程。即程序是一步一步地按照一定的顺序从头到尾执行一系列的函数。面向对象是一种以事物为中心的编程思想。即当解决一个问题时,面向对象会从这些问题中抽象出一系列对象,再抽象出这些对象的属性和方法,让每个对象去执行自己的方法。值得指出的是,面向对象中的方法相当于面向过程中的函数。

面向过程的优点是性能比面向对象高,因为类调用时需要实例化,比较消耗资源,例如单片机、嵌入式、Linux/Unix等对性能要求高的通常采用面向过程开发;其缺点是没有面向对象易维护、易复用、易扩展。

面向对象的优点是易维护、易复用、易扩展,由于面向对象有封装、继承、多态性的特性,可以设计出低耦合的系统,使系统更加灵活;其缺点是性能比面向过程低。

  1. 类和对象:类是对象的模板,对象是类的实例化

类与对象是整个面向对象中最基本的组成单元。其中,类是抽象的概念集合,表示的是一个共性的产物,类中定义的是属性和行为(方法);对象是一种个性的表示,表示一个独立而具体的个体。可以用一句话来总结类和对象的区别:类是对象的模板,对象是类的实例。类只有通过对象才可以使用,在开发中先产生类,再产生对象。类不能直接使用,对象是可以直接使用的。

  1. 类的变量类型

(1)成员变量:成员变量是定义在类体中,方法体之外的变量。这种变量在创建对象的时候实例化。成员变量可以被类中方法、构造方法和特定类的语句块访问。
(2)局部变量:在方法(包含构造方法)和语句块中定义的变量被称为局部变量。这种变量声明和初始化都是在方法中,方法结束后,变量就会自动销毁。
(3)类变量:类变量也声明在类体中,方法体之外,但必须声明为static类型。这种变量也称为静态变量。

  1. 类的成员方法

成员方法对应类的行为,一个成员方法可以不带参数,也可以带一个或若干个参数,这些参数可以是对象也可以是基本数据类型的变量,同时,成员方法可以有返回值也可以不返回任何值,返回值可以是计算结果也可以是其他数值和对象。

  1. 类的构造方法和析构方法

在类中除了成员方法,还存在两种特殊类型的方法:构造方法和析构方法:

  • 构造方法是一个与类同名的方法,对象的创建就是通过构造方法完成的。每当类实例化一个对象时,类都会自动调用构造方法。构造方法没有返回值,每个类都有构造方法,一个类可以有多个构造方法。如果没有显式地为类定义构造方法,C++编译器将会为该类提供一个默认的无参构造方法。注意,如果在类中定义的构造方法都不是无参的构造方法,那么编译器也不会为类设置一个默认的无参构造方法,当试图调用无参构造方法实例化一个对象时,编译器会报错。所以只有在类中没有定义任何构造方法时,编译器才会在该类中自动创建一个不带参数的构造方法。
  • 析构方法与构造方法相反,当对象结束其生命周期时,例如对象所在的方法已经调用完毕,那么系统会自动执行析构方法。通常建立一个对象需要用到new自动调用构造方法开辟出一片内存空间,delete会自动调用析构方法释放内存。C++中可以通过析构方法来清理类的对象,析构方法没有任何参数和返回值类型,在对象销毁时自动调用。
#include <iostream>
using namespace std;class CalcTime
{private:int mHour,mMin,mSec;public:static const int TIME_VAL_HOUR = 0x01;static const int TIME_VAL_MIN  = 0x02;static const int TIME_VAL_SEC  = 0x03;//当tick的值在0到86399之间时,才允许访问获取的时间值int calcTime(int tick){int validFlag =0;if(tick>=0 && tick<=86400){validFlag = 1;mHour = tick / 3600;mMin = (tick % 3600)/60;mSec = (tick % 3600)%60;}return validFlag;}//外部接口,输出转换的时间值int getTimeVal(int type){int timeVal = 0;switch(type){case TIME_VAL_HOUR:timeVal = mHour;break;case TIME_VAL_MIN:timeVal = mMin;break;case TIME_VAL_SEC:timeVal = mSec;break;defalut:break;}return timeVal;}};class ConverTime
{private:CalcTime ct;public://获取转换的时间并打印void dispTime(int tick){int hour,min,sec;if(ct.calcTime(tick)==1){hour = ct.getTimeVal(ct.TIME_VAL_HOUR);min  = ct.getTimeVal(ct.TIME_VAL_MIN);sec  = ct.getTimeVal(ct.TIME_VAL_SEC);cout<<"CurrentTime: "<<hour<<"-"<<min<<"-"<<sec<<endl;}}};int main()
{ConverTime convert;int tick = 0;cout<<"请输入tick的值"<<endl;cin>>tick;convert.dispTime(tick);return 0;
}

2. 类的继承

继承是一种新建类的方式,新建的类被称为子类,被继承的类成为父类,继承是类与类之间的关系,可以减少代码冗余,父类拥有一些基本的属性和方法,而子类在父类的基础上拥有各自的特点。

继承有以下优点:

  1. 代码重用性高,系统出错概率低
  2. 代码扩展性高,开发灵活
  3. 代码冗余度低,开发快

缺点如下:

  1. 继承是侵入性的,只要继承,就必须拥有父类的属性和方法
  2. 子类拥有父类的属性和方法,增加子类代码的约束,降低代码灵活性
  3. 当父类的常量、变量和方法发生改变时,需要考虑子列的修改,在缺乏规范的环境下,可能导致大量的代码需要重构。

类的继承是单一继承的,一个子类只能有一个父类,一个父类可以有多个子类,子类不仅可以扩展父类的功能,也可以重写的成员方法(多态)

继承的方式:

  1. 共有继承(public):父类的public成员和protected成员分别写到子类的public成员和protected成员中,而父类的private成员,
    则被分到一个特殊的区域,只能通过父类原有的方法访问。
  2. 私有继承(private):父类的public成员和protected成员写到子类的private成员中,而父类的private成员,
    则被分到一个特殊的区域,只能通过父类原有的方法访问。
  3. 保护继承(protected):父类的public成员和protected成员写到子类的protected成员中,而父类的private成员,
    则被分到一个特殊的区域,只能通过父类原有的方法访问。

下文中创建了父类CalcTime,计算小时和分钟值,子类CalcALLTime继承父类的同时,还完成计算秒值,检验tick的合法性,以及显示时间等方法。

#include <iostream>
using namespace std;//基类
class CalcTime
{private:int mHour,mMin;public:int mSec;static const int TIME_VAL_HOUR = 0x01;static const int TIME_VAL_MIN  = 0x02;int getTimeVal(int type,int tick){int timeVal = 0;switch(type){case TIME_VAL_HOUR:timeVal = tick/3600;break;case TIME_VAL_MIN:timeVal = (tick%3600)/60;break;default:break;}return timeVal;}};class CalcALLTime: public CalcTime
{public://外部接口,输出转换的秒值int getSecVal(int tick){int timesec = 0;mSec = (tick%3600)/60;timesec = mSec;return timesec;}int calcFlag(int tick){int validFlag = 0;if(tick>=0&&tick<=86400){validFlag = 1;}return validFlag;}void dispTime(int tick){int hour,min,sec;if(calcFlag(tick) == 1){hour = getTimeVal(TIME_VAL_HOUR,tick);min = getTimeVal(TIME_VAL_MIN,tick);sec = getSecVal(tick);cout<<"Current Time: "<<hour<<":"<<min<<":"<<sec<<endl;}}};int main()
{CalcALLTime ct;int tick = 0;cout<<"请输入Tick的值"<<endl;cin>>tick;ct.dispTime(tick);return 0;
}

3. 类的多态

多态是指相同的行为可能导致不同的结果,在定义类时:如果类的某个方法可能在后续继承的过程中被重写,则可以用virt关键字修饰,这个方法就具备了多态的特性。

对于重写的方法具有以下要求:

  1. 父类方法和子类重写的方法参数列表、返回值、方法名必须相同
  2. 子类重写的方法权限需要和父类权限相同或者更高(类当中:public权限最低,private权限最高)
  3. 父类中方法权限为private时,该方法不可重写
  4. 如果父类方法抛出异常,那么子类重写的方法也要抛出异常,且抛出的异常不能多于父类

下文中创建了父类CalcTime,子类CalcMin和CalcSec,重写的方法为getTimeVal,父类计算小时值,子类分别计算分钟和秒值

#include <iostream>
using namespace std;//基类
class CalcTime
{private:int mHour;public://这个方法加上virt关键字修饰,可被其继承的子类重写,成为虚方法,实现多态virtual int getTimeVal(int tick){mHour = tick/3600;return mHour;}};//类CalcMin通过公有继承的方式继承基类CalcTime
class CalcMin: public CalcTime
{private:int mMin;public://外部接口,输出转换的时间值int getTimeVal(int tick){mMin = (tick%3600)/60;return mMin;}};//类CalcSec通过公有继承的方式继承基类CalcTime
class CalcSec: public CalcTime
{private:int mSec;public://外部接口,输出转换的时间值int getTimeVal(int tick){mSec = (tick%3600)%60;return mSec;}};class ConvertTime
{private:CalcTime *ct;CalcTime ctHour;CalcMin  ctMin;CalcSec  ctSec;public://获取转换的时间,并打印出来void dispTime(int tick){int hour,min,sec;if(tick>=0 && tick<=86400){
/* 			ct = &ctHour;hour = ct->getTimeVal(tick);ct = &ctMin;min = ct->getTimeVal(tick);ct = &ctSec;sec = ct->getTimeVal(tick); */hour = ctHour.getTimeVal(tick);min  = ctMin.getTimeVal(tick);sec  = ctSec.getTimeVal(tick);cout<<"Current Time: "<<hour<<":"<<min<<":"<<sec<<endl;}else{	cout<<"请输入正确的值"<<endl;}}
};
int main()
{ConvertTime ct;int tick = 0;cout<<"请输入Tick的值"<<endl;cin>>tick;ct.dispTime(tick);return 0;
}

4. 方法重载

如果一个类中包含两个及两个以上方法名字相同,但参数列表不同(与返回值无关)的方法,那么这两个方法成为重载方法。

重载方法,具有以下特点:

  1. 同一个类中方法名相同,
  2. 参数列表不同(其他部分,返回值类型,修饰符与方法重载无关):数量和类型不同都可以重载
#include <iostream>
using namespace std;//基类
class CalcTime
{public:int mHour,mMin,mSec;void calcTimeVal(bool hourFlag,int tick){if(hourFlag == 1 && tick>=0&&tick<=86400){mHour = tick/3600;cout<<"Current Time: "<<mHour<<endl;}}void calcTimeVal(bool hourFlag,bool minFlag,int tick){if(hourFlag == 1 && minFlag ==1 &&tick>=0&&tick<=86400){mHour = tick/3600;mMin = (tick%3600)/60;cout<<"Current Time: "<<mHour<<":"<<mMin<<endl;}}void calcTimeVal(bool hourFlag,bool minFlag,bool secFlag,int tick){if(hourFlag == 1 && minFlag ==1 && secFlag == 1 &&tick>=0&&tick<=86400){mHour = tick/3600;mMin = (tick%3600)/60;mSec = (tick%3600)%60;cout<<"Current Time: "<<mHour<<":"<<mMin<<":"<<mSec<<endl;}}
};
int main()
{CalcTime ct;int tick = 0;cout<<"请输入Tick的值"<<endl;cin>>tick;ct.calcTimeVal(1,tick);ct.calcTimeVal(1,1,tick);ct.calcTimeVal(1,1,1,tick);return 0;
}

5. 抽象类

带有纯虚方法的类成为抽象类。也属于类的一种,是为了抽象和设计的目的而建立的,处于继承层次结构的较上层

纯虚方法的声明格式如下:
virtu 返回值类型 方法名 (参数表) = 0;

在C++里面对于抽象类有以下规定:

  1. 抽象类只能用作其他类的基类,不能建立抽象类对象
  2. 抽象类不能作为函数参数、返回值和强制类型转换使用
  3. 可以定义指向抽象类的指针和引用,此指针可以指向它的派生类,进而实现多态性

抽象类的应用:
通常定义一个类时,会定义类具体的属性和方法,但在某些情况下只知道一个类需要那些属性和方法,不知道其方法具体是什么,这个时候就需要用到抽象类。

比如:老板说要做一个成本80以内的电子血压计,能测量收缩压、舒张压、脉率,那么这就是一个抽象类。包括两个抽象属性:成本80以内和电子血压计;三个抽象方法:测量收缩压、舒张压和脉率。在实际应用时,就可以按照抽象类设计产品,抽象类就像一个大纲,规范了大概的方向。

抽象类除了不能实例化对象,类的其他功能依旧存在,与普通类是一样的。抽象类不能实例化对象,所以必须被继承后,才能被使用。

#include <iostream>
using namespace std;//基类
class Time
{public:int mHour,mMin,mSec;//用于告诉编译器当前声明为纯虚方法,使得Time为抽象类virtual void dispTime() = 0;
};//CalcTime类通过公有继承的方式继承Time类
class CalcTime: public Time
{public:void CalcHour(int tick){mHour = tick / 3600;}void CalcMin(int tick){mMin = (tick%3600) / 60;}void CalcSec(int tick){mSec = (tick%3600) % 60;}void dispTime( ){cout<<"Current Time: "<<mHour<<":"<<mMin<<":"<<mSec<<endl;}};int main()
{CalcTime ct;int tick = 0;cout<<"请输入Tick的值"<<endl;cin>>tick;ct.CalcHour(tick);ct.CalcMin(tick);ct.CalcSec(tick);ct.dispTime();return 0;
}

6. 接口类

接口描述了类的行为和功能,而不需要完成类的特定实现,在C++中接口应满足以下规定:

  1. 类中没有定义任何成员变量
  2. 所有的成员方法都是公有的
  3. 所有的成员方法都是纯虚方法
  4. 接口是一种特殊的抽象类
  5. 接口一旦被继承, 需要重写所有成员和方法才能创建对象
#include <iostream>
using namespace std;//接口,可继承,不可创建对象
class Interface
{public:virtual void dispTime() = 0;virtual void CalcHour(int tick) = 0;virtual void CalcMin(int tick)  = 0;virtual void CalcSec(int tick)  = 0;
};//CalcTime类通过公有继承的方式继承Interface类
class CalcTime: public Interface
{public:int mHour,mMin,mSec;void CalcHour(int tick){mHour = tick / 3600;}void CalcMin(int tick){mMin = (tick%3600) / 60;}void CalcSec(int tick){mSec = (tick%3600) % 60;}void dispTime( ){cout<<"Current Time: "<<mHour<<":"<<mMin<<":"<<mSec<<endl;}};int main()
{CalcTime ct;int tick = 0;cout<<"请输入Tick的值"<<endl;cin>>tick;ct.CalcHour(tick);ct.CalcMin(tick);ct.CalcSec(tick);ct.dispTime();return 0;
}

7. 异常处理

  1. 异常:
    异常是指程序运行时不正确的状态,如数组越界,整数除零等程序需要报错的状态,一旦程序发送异常,在异常之后的语句都不会执行。

  2. 异常处理
    在C++中,异常处理机制会使用到捕捉和处理异常的try…catch语句,其中try语块中是可能发送异常的代码,catch语块用来处理异常,
    try之后可以有多个catch语块,示例代码如下:

try
{//可能产生异常的代码块
}
catch(ExceptionName e1)
{// 处理异常1
}
catch(ExceptionName e2)
{// 处理异常2
}
......
catch(ExceptionName en)
{// 处理异常n
}
  1. 抛出异常
    通过throw语句可以在代码块中的任意区域抛出异常,
    throw语句的操作数可以是任意表达式,表达式结果的类型决定了抛出的异常类型

示例代码如下:

if(tick<0 || tick>86400)
{throw "tick的值不符合要求"; 	//抛出异常信息
}
else
{cout<<"tick的值为"<<tick<<endl;
}
  1. 异常处理机制的意义
  • 相对于异常处理机制,异常处理可以面对更为复杂的情景,比如文件的输入/输出异常、文件读写异常,这写都是if语句无法处理的
  • 异常处理机制体现了一种对错误进行有效控制的思想,更加符合面向对象的特点。
#include <iostream>
using namespace std;//CalcTime
class CalcTime
{public:int mHour,mMin,mSec;void calcTimeVal(int tick){if(tick>=0&&tick<=86400){mHour = tick / 3600;mMin = (tick%3600) / 60;mSec = (tick%3600) % 60;cout<<"Current Time: "<<mHour<<":"<<mMin<<":"<<mSec<<endl;}else{throw "Tick value is not valid!!!"; //抛出异常信息}}void dispTime( ){}};int main()
{CalcTime ct;int tick = 0;cout<<"请输入Tick的值"<<endl;cin>>tick;//保护代码try{ct.calcTimeVal(tick);}//捕获异常信息并输出提示catch(const char* e){cout<<e<<endl;}return 0;
}

http://www.ppmy.cn/news/1529299.html

相关文章

(学习记录)使用 STM32CubeMX——GPIO引脚输出配置

学习总结&#xff1a;&#xff08;学习总结&#xff09;STM32CubeMX HAL库 学习笔记撰写心得https://blog.csdn.net/Wang2869902214/article/details/142435481 STM32F103C8T6的GPIO引脚输出配置 时钟配置 &#xff08;学习记录&#xff09;使用 STM32CubeMX——配置时钟&…

企业微信应用消息收发实施记录

一、前置配置 1.1 进入我的企业页面&#xff0c;记录下企业ID。 1.2 创建企微应用&#xff0c;记录下应用的 AgentId 和 Secret。 1.3 设置应用的企业可信IP&#xff0c;将服务器公网 IP 填入即可。 1.4 设置应用接收消息API 填入服务器 API 地址&#xff0c;并记录下随机获取…

numpy.dot example

文章目录 1. 左行右列2. numpy.dot 1. 左行右列 假设有两个矩阵A,P 对于矩阵A来说&#xff0c; AP矩阵中&#xff0c;P在A的右边&#xff0c;那么对于矩阵A来说是对矩阵A进行列变换PA矩阵中&#xff0c;P在A的左边&#xff0c;那么对于矩阵A来说是对矩阵A进行行变换 A [ 1 …

[PICO VR眼镜]眼动追踪串流Unity开发与使用方法,眼动追踪打包报错问题解决(Eye Tracking/手势跟踪)

前言 最近在做一个工作需要用到PICO4 Enterprise VR头盔里的眼动追踪功能&#xff0c;但是遇到了如下问题&#xff1a; 在Unity里面没法串流调试眼动追踪功能&#xff0c;根本获取不到Device&#xff0c;只能将整个场景build成APK&#xff0c;安装到头盔里&#xff0c;才能在…

考研408《操作系统》复习笔记,第一章《概述》

一、是啥玩意&#xff1f; 计算机操作系统就是&#xff1a; 操控、管理整个计算机软件和硬件的资源、并合理分配计算机工作、资源 &#xff08;人话&#xff09;&#xff1a;操作系统是计算机系统资源的管理者 &#xff1b; 以给用户和其他软件提供更方便的接口和环境 &#x…

解决使用nvm管理node版本时提示npm下载失败的问题

目录 一、引言 二、解决步骤 1. 访问该网站下载对应版本的npm Release v6.14.18 npm/cli GitHubthe package manager for JavaScript. Contribute to npm/cli development by creating an account on GitHub.https://github.com/npm/cli/releases/tag/v6.14.18 2. 解压到n…

速盾:cdn防御攻击的时候会影响运行吗?

CDN&#xff08;内容分发网络&#xff09;是一种分布式架构&#xff0c;旨在提高网站的性能和可用性。它通过将内容存储在全球分布的边缘服务器上来分发网站的静态资源&#xff0c;以降低延迟并提高传输速度。除了提供高速的内容传输外&#xff0c;CDN还可以提供一定程度的安全…

STM32篇:STM32CubeMX的安装

一.介绍与安装 1.作用 通过界面的方式&#xff0c;快速生成工程文件。 2.下载 官网 https://www.st.com/zh/development-tools/stm32cubemx.html#overview 3.安装 一路下一步&#xff0c;建议不要安装在C盘 4.配置 更新固件包位置&#xff08;比较大&#xff0c;默认在…