C++提高编—(模板,泛型,异常处理)

一 模板

1.1 模板概论

以下图为例子,提供了三个西装的证件照,谁都可以取拍照,可以是小孩,男女人,也可以是某些动物等等等。n那么我们这个模板也是这样,它可以是任何类型,基础类型,class型,等等等等。且会根据你的指定类型编程相对类型(配对)

模板的特点:

  • 模板不可以直接使用,它只是一个框架

  • 模板的通用并不是万能的

1.2 函数模板

1.2.1 函数模板概念及应用

语法:

template<typename T>
//函数声明或定义

解释:

template --- 声明创建模板

typename --- 表面其后面的符号是一种数据类型,可以用class代替

T --- 通用的数据类型,名称可以替换,通常为大写字母

代码示例:

此定义了两个int的变量赋值成功了,这时的T就成为了int类型的

#include <iostream>
using namespace std;template <typename T>
int test(T &a, T &b)
{return a + b;
}int main(int argc, char const *argv[])
{// 原代码传递的是临时常量,而函数模板参数是引用,需要传递变量int num1 = 1;int num2 = 2;// test(num1, num2);// 原函数模板要求两个参数类型一致,这里将 num2 转换为 int 类型以匹配参数列表cout << test(num1, num2) << endl;return 0;
}

 注意事项:

函数模板 会编译两次

第一次:是对函数模板本身编译

第二次:函数调用处将T的类型具体化

函数模板目标:模板是为了实现泛型,可以减轻编程的工作量,提高函数的重用性

1.2.2 函数模板重载

重载,即在同一作用域下,函数名相同,类型or参数什么的不同。

// 函数模板重载
template <typename T>
void printer(T a, T b)
{cout << "a=" << a << "  b=" << b << endl;cout << "2个参数函数模板执行" << endl;
}
// 这样重新声明模板类型T,因为一次声明只对当前函数生效
template <typename T>
void printer(T a)
{cout << "a=" << a << endl;cout << "1个参数函数模板执行" << endl;
}
int main()
{int a = 10;int b = 20;printer(a);printer(a,b);
}

1.2.3 函数模板与普通函数区别

  • 普通函数调用时可以发生自动类型转换(隐式类型转换)

  • 函数模板调用时,如果利用自动类型推导,不会发生隐式类型转换

  • 如果利用显示指定类型的方式,可以发生隐式类型转换

  • 总结:建议使用显示指定类型的方式,调用函数模板,因为可以自己确定通用类型T

#include <iostream>
using namespace std;// 普通函数
int myAdd01(int a, int b)
{return a + b;
}// 函数模板
template <class T>
T myAdd02(T a, T b)
{return a + b;
}// 使用函数模板时,如果用自动类型推导,不会发生自动类型转换,即隐式类型转换
void test01()
{int a = 10;int b = 20;char c = 'c';cout << myAdd01(a, c) << endl; // 正确,将char类型的'c'隐式转换为int类型  'c' 对应 ASCII码 99// myAdd02(a, c); // 报错,使用自动类型推导时,不会发生隐式类型转换myAdd02<int>(a, c); // 正确,如果用显示指定类型,可以发生隐式类型转换
}int main(int argc, char const *argv[])
{test01();system("pause");return 0;
}

1.3 类模板

1.3.1 类模板基本概念

类模板作用:

  • 建立一个通用类,类中的成员 数据类型可以不具体制定,用一个虚拟的类型来代表。

语法:

template<typename T>
//类

解释:

template --- 声明创建模板

typename --- 表面其后面的符号是一种数据类型,可以用class代替

T --- 通用的数据类型,名称可以替换,通常为大写字母

示例:

#include <iostream>
using namespace std;// 函数模板
template <class Name, class Age>
class demo
{
public:demo(Name name, Age age){this.name = name;this.age = age;}~demo();
};int main(int argc, char const *argv[])
{system("pause");return 0;
}

1.3.2 类模板成员函数类外实现

1.3.3 类模板做函数参数

学习目标:

  • 类模板实例化出的对象,向函数传参的方式

一共有三种传入方式:

  1. 指定传入的类型 --- 直接显示对象的数据类型

  2. 参数模板化 --- 将对象中的参数变为模板进行传递

  3. 整个类模板化 --- 将这个对象类型 模板化进行传递

总结:

  • 通过类模板创建的对象,可以有三种方式向函数中进行传参

  • 使用比较广泛是第一种:指定传入的类型

 

#include <iostream>
#include <string>
using namespace std;
// 类模板
template <class NameType, class AgeType = int>
class Person
{
public:Person(NameType name, AgeType age){this->mName = name;this->mAge = age;}void showPerson(){cout << "name: " << this->mName << " age: " << this->mAge << endl;}public:NameType mName;AgeType mAge;
};// 1、指定传入的类型
void printPerson1(Person<string, int> &p)
{p.showPerson();
}
void test01()
{Person<string, int> p("孙悟空", 100);printPerson1(p);
}// 2、参数模板化
template <class T1, class T2>
void printPerson2(Person<T1, T2> &p)
{p.showPerson();std::string typeName1 = "未知类型";std::string typeName2 = "未知类型";if (typeid(T1) == typeid(std::string)){typeName1 = "std::string";}if (typeid(T2) == typeid(int)){typeName2 = "int";}cout << "T1的类型为: " << typeName1 << endl;cout << "T2的类型为: " << typeName2 << endl;
}
void test02()
{Person<string, int> p("猪八戒", 90);printPerson2(p);
}// 3、整个类模板化
template <class T>
void printPerson3(T &p)
{std::string typeName = "未知类型";if (typeid(T) == typeid(Person<std::string, int>)){typeName = "Person<std::string, int>";}cout << "T的类型为: " << typeName << endl;p.showPerson();
}
void test03()
{Person<string, int> p("唐僧", 30);printPerson3(p);
}int main()
{test01();test02();test03();system("pause");return 0;
}

1.3.4 类模板与继承

当类模板碰到继承时,需要注意一下几点:

  • 当子类继承的父类是一个类模板时,子类在声明的时候,要指定出父类中T的类型

  • 如果不指定,编译器无法给子类分配内存

  • 如果想灵活指定出父类中T的类型,子类也需变为类模板

1.3.4.1 普通类继承
#include <iostream>
#include <string>
using namespace std;
// 父类模板
template <class T>
class Base
{T m;
};// class Son:public Base  //错误,c++编译需要给子类分配内存,必须知道父类中T的类型才可以向下继承
class Son : public Base<int> // 必须指定一个类型
{
};
void test01()
{Son c;
}// 类模板继承类模板 ,可以用T2指定父类中的T类型
template <class T1, class T2>
class Son2 : public Base<T2>
{
public:Son2(){cout << typeid(T1).name() << endl;cout << typeid(T2).name() << endl;}
};void test02()
{Son2<int, char> child1;
}int main()
{test01();test02();system("pause");return 0;
}

1.3.6 类模板头文件和源文件分离问题

学习目标:

  • 掌握类模板成员函数分文件编写产生的问题以及解决方式

问题:

  • 类模板中成员函数创建时机是在调用阶段,导致分文件编写时链接不到

解决:

  • 解决方式1:直接包含.cpp源文件

  • 解决方式2:将声明和实现写到同一个文件中,并更改后缀名为.hpp,hpp是约定的名称,并不是强制

推荐写hpp文件

#pragma once
#include <iostream>
using namespace std;
#include <string>template<class T1, class T2>
class Person {
public:Person(T1 name, T2 age);void showPerson();
public:T1 m_Name;T2 m_Age;
};//构造函数 类外实现
template<class T1, class T2>
Person<T1, T2>::Person(T1 name, T2 age) {this->m_Name = name;this->m_Age = age;
}//成员函数 类外实现
template<class T1, class T2>
void Person<T1, T2>::showPerson() {cout << "姓名: " << this->m_Name << " 年龄:" << this->m_Age << endl;

1.3.7 友元类模板

直接举例说明,不做过多描述

template <class T1,class T2>
class Demo1
{template <class T3, class T4> friend void test1(Demo1<T3, T4> obj);
private:T1 a;T2 b;
public:Demo1(T1 a, T2 b){this->a = a;this->b = b;}
};
// 全局函数模板
template <class T3, class T4>
void test1(Demo1<T3, T4> obj)
{cout << obj.a << "  " << obj.b << endl;
}
1.3.7.1 全局函数模板作为类模板的友元
template <class T1,class T2>
class Demo1
{template <class T3, class T4> friend void test1(Demo1<T3, T4> obj);
private:T1 a;T2 b;
public:Demo1(T1 a, T2 b){this->a = a;this->b = b;}
};
// 全局函数模板
template <class T3, class T4>
void test1(Demo1<T3, T4> obj)
{cout << obj.a << "  " << obj.b << endl;
}
1.3.7.2 类中成员函数作为类模板的友元
template <class T1, class T2>
class Demo1;class Demo2
{
public:template<class T5, class T6>void test2(Demo1<T5, T6> obj){cout << "类中函数模板打印:" << obj.a << "  " << obj.b << endl;}
};template <class T1,class T2>
class Demo1
{template<class T5, class T6> friend void Demo2::test2(Demo1<T5, T6> obj);
private:T1 a;T2 b;
public:Demo1(T1 a, T2 b){this->a = a;this->b = b;}
};
1.3.7.3 普通函数作为类模板的友元
template <class T1,class T2>
class Demo1
{friend void test2(Demo1<int, int> obj);
private:T1 a;T2 b;
public:Demo1(T1 a, T2 b){this->a = a;this->b = b;}
};void test2(Demo1<int,int> obj)
{cout << "普通全局函数打印:" <<  obj.a << "  " << obj.b << endl;
}

1.4 综合练习

设计一个数组模板类(MyArray),完成对不同类型元素的管理。不仅能操作基本数据类型,还可以操作自定义数据类型

还是一个动态数组,可以扩容等操作

二 泛型(与Java对比) 

详述在之前写的文章,感兴趣的同学们,可以去看看。

zz​​​​​​​​​​​​​Java 自定义异常(案例)throws与throw的区别_throw的例子分数不合法-CSDN博客

Java 异常处理之Throwable的常用成员方法的概述_throwable getmessage get detail-CSDN博客

Java 自定义异常(案例)throws与throw的区别_throw的例子分数不合法-CSDN博客

三 异常处理

3.1 基本语法

// 写一个计算两个数相除的算法
int division(int a, int b)
{if (b == 0){// 对于函数的返回值是可以忽略的,但是异常不可以//return -1;	// -1表示参数有问题throw - 1;	// 抛出异常,throw是关键字,-1是异常值,异常值可以随便写// 如果抛出异常,不会返回-1,而是该函数直接在这个地方结束,进入到catch}return a / b;	// 否则就返回正常的除法结果
}
void fun1()
{int a = 10;int b = 0;// 抛出异常,就要捕获异常,否则程序将直接崩溃int res;try{// 把会抛出异常的语句放到try中res = division(a, b);}catch (int e)// 异常值类型 异常值{//并要在catch中处理捕获到异常以后要做的事情res = 0;cerr << "int类型异常" << endl;}// 当然也可以写多个catch块catch (char e){res = 0;cerr << "char类型异常" << endl;}catch (...)	// 捕获其他所有类型异常{res = 0;cerr << "其他类型异常" << endl;}int res1 = res * 100;cout << "(10/0)*100=" << res1 << endl;
}

3.2 栈解旋(unwinding)

从进入 try 块起,到异常被抛掷前,这期间在栈上构造的所有对象,都会被自动析构。析构的顺序与构造的顺序相反,这一过程称为栈的解旋(unwinding).

class Demo
{
public:int a;
public:Demo(){cout << "无参构造" << endl;}Demo(int a){this->a = a;cout << "有参构造;a=" << this->a << endl;}~Demo(){cout << "析构函数;a=" << this->a << endl;}
};void fun1()
{try{Demo ob1(10);Demo ob2(20);Demo ob3(30);// 抛出异常时,当前程序就会自动进入catch处理异常,因此要将局部变量 ob3 ob2 ob1依次释放throw 1;}catch (int){cout << "int类型异常" << endl;}catch (...){cout << "其他类型异常" << endl;}}

2.3 函数不能抛出异常- 了解


// 使用 noexcept 规格来指定函数是否可以抛出异常
// 该函数不允许抛出异常
void test04()noexcept(true)
{throw 1;
}
// 该函数可以抛出异常
void test05()noexcept(false)
{throw 1;
}
void fun1()
{try{test05();}catch (int){cout << "int类型异常" << endl;}catch (char){cout << "char类型异常" << endl;}catch (const char *){cout << "const char *类型异常" << endl;}catch (float){cout << "float类型异常" << endl;}catch (...){cout << "其他类型异常" << endl;}
}

异常接口说明在不同的编译器,编译结果是不一样的。

3.4 异常的多态使用

// 定义一个基本的父类异常类
class BaseException
{
public:virtual void printExceptionMsg() {};
};
// 定义一个空指针异常,继承于BaseException
class NullPointerException :public BaseException
{
public:void printExceptionMsg(){cout << "null pointer exception!" << endl;}
};
// 定义一个数组下标越界异常,继承于BaseException
class IndexOutOfException :public BaseException
{
public:void printExceptionMsg(){cout << " Index out of range!" << endl;}
};
void fun1()
{try{throw IndexOutOfException();}// 如果要处理多种异常,没必要在这个地方写N多个catch// 让它们继承于同一个父类,然后在这个地方用父类引用接收不同子类对象就可以// 这就是之前讲过的多态catch (BaseException &e){e.printExceptionMsg();}
}

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

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

相关文章

Python图像处理基础(六)

Python图像处理基础(六) 文章目录 Python图像处理基础(六)3.4 双层图像3.5 具有更多色阶的位图数据3.6 基于调色板的图像3.6.1 超过 256 种颜色的图像3.7 处理透明度3.7.1 Alpha 通道3.7.2 透明调色板条目3.7.3 透明颜色3.8 隔行扫描和交替像素排序3.4 双层图像 某些类型的…

卷积神经网络(一)

第七章 卷积神经网络 从今天开始学习卷积神经网络的内容。 本章的主题是卷积神经网络&#xff08;Convolutional Neural Network&#xff0c;CNN&#xff09;。 CNN被用于图像识别、语音识别等各种场合&#xff0c;在图像识别的比赛中&#xff0c;基于 深度学习的方法几乎都以…

OpenCV 多边形绘制与填充

一、知识点 1、void polylines(InputOutputArray img, InputArrayOfArrays pts, bool isClosed, const Scalar & color, int thickness 1, int lineType LINE_8, int shift 0 ); (1)、在图像上绘制多边形曲线。 (2)、参数说明: img: 输入、输出参数&#xff0…

C#接口代码记录

using System;namespace InterfacesExample {// 定义接口public interface INBAPlayable{void KouLan();}public interface ISupermanable{void Fly();}// 基类public class Person{public void CHLSS(){Console.WriteLine("人类吃喝拉撒睡");}}// Student 类实现多个…

SpringDataJpa实体类中属性顺序与数据库中生成字段顺序不一致的问题

自己写的代码覆盖hibernate中的代码 翻了翻源码发现&#xff0c;很多地方都是使用LinkedHashMap或者是List来传输Entity里面的fields&#xff0c;于是感觉Hibernate应该是考虑到使用Entity里面定义的fields的顺序来实现建表语句里的表字段顺序的。   于是就一步步跟踪下去&…

软件架构期末复习

题型 填空题 20分,2分/空,10空 选择题 30分,2分/题,15题 简答题 30分,6分/题,5题(概念+分析) 案例分析题 20分,5个小题(综合) 分值:体系结构、设计模式各占50% 考试内容 体系结构 SA基础(SA03PPT):SA概念、SA与软件过程(阶段)的关系、SA核心概念模型(重要…

Oracle ADG 日常巡检指南

一、基础状态检查 数据库角色与模式 SELECT db_unique_name, open_mode, database_role, switchover_status FROM v$database;预期状态&#xff1a; 主库&#xff1a;OPEN_MODEREAD WRITE, DATABASE_ROLEPRIMARY备库&#xff1a;OPEN_MODEREAD ONLY WITH APPLY, DATABASE_ROLE…

【MV】key_moments 与 continuous_timeline的编排权衡

一、编排顺序: key_moments → continuous_timeline* 建议使用顺序:key_moments → continuous_timeline 📊 两者关系 key_moments:从continuous_timeline中精选出来的重点(约11个关键时间点)continuous_timeline:完整的时间轴(37个片段,覆盖每句歌词)🎭 实际编…

Tomcat线程模型

目录 1 Linux I/O模型 2 Linux I/O模型分类 3 Tomcat支持的I/O模型 4 Tomcat I/O模型选型 5 Tomcat NIO实现 6 Tomcat异步IO实现 1 Linux I/O模型 I/O&#xff1a;在计算机内存和外部设备之间拷贝数据的过程程序通过cpu向外部设备发出读指令&#xff0c;数据从外部设置拷贝至内…

最新Spring Security实战教程企业级安全方案设计实现

最新Spring Security实战教程&#xff08;十七&#xff09;企业级安全方案设计 - 多因素认证&#xff08;MFA&#xff09;实现 1. 前言2. 为什么需要多因素认证&#xff1f; 传统认证的风险MFA的核心优势常见多因素认证实现方案 3. 多因素认证的核心原理4. 系统架构与流程设计…

十九、【用户管理与权限 - 篇一】后端基础:用户列表与角色模型的初步构建

【用户管理与权限 - 篇一】后端基础:用户列表与角色模型的初步构建 前言准备工作第一部分:回顾 Django 内置的 `User` 模型第二部分:设计并创建 `Role` 和 `UserProfile` 模型第三部分:创建 Serializers第四部分:创建 ViewSets第五部分:注册 API 路由第六部分:后端初步测…

大话软工笔记—架构的概要设计

架构的概要设计是在需求工程分析成果的基础之上对整个系统进行的顶层规划&#xff0c;重点是确定设计规范&#xff08;理念、主线等&#xff09;&#xff0c;从大的范围和高度对业务进行规划和设计&#xff0c;架构概要设计的成果“业务架构图”&#xff0c;是后续各阶段设计的…

Flink CDC —部署模式

一、Standalone 模式 独立模式是Flink最简单的部署模式。本简短指南将向您展示如何下载最新稳定版本的Flink&#xff0c;安装和运行它。 您还将运行一个示例Flink CDC作业&#xff0c;并在web UI中查看它。 1、准备 Flink在所有类似UNIX的环境中运行&#xff0c;即Linux、Mac…

day029-Shell自动化编程-计算与while循环

文章目录 1. read 交互式初始化变量1.1 案例-安装不同的软件1.2 案例-比较大小 2. 计算2.1 bc2.2 awk2.3 expr2.4 let2.5 案例-计算内存的空闲率2.6 案例-检查域名过期时间和https证书过期时间 3. 循环3.1 循环控制语句3.2 for循环-c语言格式3.3 while循环3.3.1 案例-猜数字3.3…

华为云Flexus+DeepSeek征文 | 基于华为云ModelArts Studio打造AingDesk AI聊天助手

华为云FlexusDeepSeek征文 | 基于华为云ModelArts Studio打造AingDesk AI聊天助手 引言一、ModelArts Studio平台介绍华为云ModelArts Studio简介ModelArts Studio主要特点 二、安装AingDesk应用AingDesk应用介绍下载地址安装AingDesk工具 三、开通DeepSeek-R1-0528商用服务访问…

深度解析Git错误:`fatal: detected dubious ownership in repository` 的根源与解决方案

如果你是在使用自己的移动硬盘&#xff08;U盘&#xff09;操作项目时遇到的这个问题直接执行git config --global --add safe.directory X:/path即可&#xff0c;只要你的移动硬盘&#xff08;U盘&#xff09;没有病毒就不会有安全问题。 深度解析Git错误&#xff1a;fatal: d…

基于Spring Boot的校园社区平台设计与实现

目录 一.&#x1f981;前言二.&#x1f981;开源代码与组件使用情况说明三.&#x1f981;核心功能1. ✅算法设计2. ✅Thymeleaf模板引擎3. ✅MyBatis Plus框架4. ✅部署项目 四.&#x1f981;演示效果1. 管理员模块1.1 用户管理1.2 浏览管理员首页1.3 论坛管理1.4 校园咨询管理…

Java 8 Map 新增方法详解

Java 8 Map 新增方法详解 1. getOrDefault 源码&#xff1a; default V getOrDefault(Object key, V defaultValue) {V v;return (((v get(key)) ! null) || containsKey(key))? v: defaultValue;}作用&#xff1a;安全获取值&#xff0c;若key不存在则返回默认值 示例&…

山东大学 2025 web数据管理期末复习总结

SDU-2025年-Web数据管理期末总结 考试题型 填空 &#xff1a;都来自于PPT中名词解释简答题&#xff1a;需要背一些公式。 根据L老师上课提及的重点一共总结了87问题。 文章目录 SDU-2025年-Web数据管理期末总结考试题型第1讲 绪论此章不考 第2讲 网络爬虫技术2.1 爬虫是什么…

Spring框架的设计模式

Spring 框架深度集成了多种经典设计模式&#xff0c;这些模式支撑了其核心功能&#xff08;如IoC、AOP&#xff09;的实现&#xff0c;以下是关键模式及其应用场景的梳理&#xff1a; 1、工厂模式 工厂模式&#xff08;Factory Pattern&#xff09;是 Java 中最常用的设计模式…