一. 模板函数
二.模板类
当一个类中存在通用类型数据,那么他就是模板类
1.模板类语法:
C++ template <class 通用类型名> class 类名{ 通用类型 成员名; }; template <class T> class base { T a; } //这就是模板类 |
- 模板类没有自动类型推导功能!! 必须用户手动实例化!!! <数据类型>

C++ #include <iostream> using namespace std; //模板类 template <class T> class base{ public: base(T a) : a(a){} private: T a; }; class base1{ public: int a ; private: int b; }; int main(int argc, char const *argv[]) { int a = 10086; // base a(a); //定义对象之前 需要先实例化 -- 指定通用类型的数据类型 base <int>a(a); //定指定通用类型的数据类型 return 0; } |
2.模板类和模板函数的区别
- 模板类可以使用默认类型 (模板函数其实也有默认类型, 但是一般不用)
C++ #include <iostream> using namespace std; //给模板类型设置默认参数 template <class T=int> class base{ public: base(T a) : a(a){} void show(){ cout << this->a << endl; } private: T a; }; int main(int argc, char const *argv[]) { //即便设置默认类型 也要写 <> base <> b(123); b.show(); //当传入的参数与默认类型不匹配 // 用户可以手动指定类型 base <string> c("world"); c.show(); return 0; } |
3.模板类可以作为函数参数进行传递
注意: 一个模板类, 不能直接通过类名作为函数的参数进行传递
解决方式1 : 指定模板类的参数列表类型
C++ void show(base<int> a){ cout << a.b << endl; } |
解决方式2 : 继续类型模板化
C++ template <class T> void show(base<T> a){ //自动类型推导 cout << a.b << endl; } |
解决方式3 : 模板函数
C++ template <class T> void show(T a){ //模板函数 -- 对参数进行 自动类型推导 cout << a.b << endl; } |
总结: 推荐使用第一种方法!!! 更直观, 代码阅读更容易
模板的用途就是为了最终的实例化, --- 实例化后内容就是固定的
注意: 定义完template , 就要直接使用, 如果后面再需要则再次定义
4.模板类成员函数在类外定义
C++ #include <iostream> using namespace std; // 定义模板类 template <class T> class base { public: //类内声明接口 base(T a); ~base(); void show(); private: T a; }; //类外定义模板类的成员函数 //构造函数 template <class T> base<T>::base(T a){ this->a = a; } //析构函数 template <class T> base<T>::~base(){ cout << "调用析构函数" << endl; } //显示接口 template <class T> void base<T>::show(){ cout << this->a << endl; } int main(int argc, char const *argv[]) { base <int> a(10010); a.show(); return 0; } //模板类 Person 两个通用类型 T 姓名 T1年龄 // 类外实现接口 : 设置成语数据 显示成员数据 构造函数和析构函数 |
5.模板类的继承
模板类不能直接被继承
解决方式:
- 指定基类的模板类型
//想要被继承
//1 . 指定基类的模板类型
class son : public base<int>{
};
- 派生类继续模板化
template<class T>
class son : public base<T>{
};
练习:
1.模板类 Person
T(姓名) A(年龄)
根据Person基类 派生出教师类Teacher
在Teacher 类中初始化Person成员并输出
设计一个通用数组类 可以存储不同的数据类型
三.补充:
c++ 中的数据成员属性
静态属性:
回顾C语言的静态变量特点:
1.静态全局变量,只能在当前文件中使用
2.修饰局部变量的时候,局部变量只能被初始化一次
3.修饰函数,只能在当前文件中使用
4.静态变量会改变数据的生命周期 (把栈空间的数据改为数据段)
类中的静态成员:
1.类中的静态成员只能在类外初始化
int base::a=100; //类外初始化
2.类中的静态成员,不包含在对象空间中,因为静态成员是存储在数据段中的。
例如: class base{
public:
static int a;} ->大小为 1 。a不在base 的空间中
3.类中的静态成员,可以直接通过 《类名::变量名》 直接调用。 (一定要是公共成员)
4.类中的所有对象,共用静态成员。
类中的静态函数:
1.类中的静态函数,不能使用this 指针, (不是对象空间中的函数)
2.类中的静态函数,不能访问类中的非静态成员数据。
(因为非静态成员数据,要定义对象后才产生空间,因为静态成员函数是先于对象存在的,静态成员函数,就无法访问)
3.静态成员函数是先于对象存在的,所以我们可以 《直接调用共有的静态成员函数》不需要创建对象!
//总结:静态成员函数的优点:1.方便用户的调用 2.不需要创建对象直接调用,节省内存空间
设计如下一个文件管理类:
C++ class file { //构造函数 //静态读取文件的内容接口 //文件的路径名 } //可以实现在不创建 file 对象的情况下,直接读取文件中的内容。 |
类中的const成员
回顾c语言中的const 变量:
C++ const int *p; //不能修改,指向的内容 int const *p;//不能修改,指向的内容 int *const p;//不能修改指向的地址 const int *const p;//不能修改指向的内容与地址 · |
找规律: 看*
如果*和p 一起的,就是内容不可变
如果是分开的,就地址不可变.
常量成员的作用
作用:提高代码的稳定性与安全性。
const int a=100;
类中的常量成员
1.类中的常量成员,必须要初始化,否则无法定义对象。 (构造函数中的参数列表初始化,默认值)
2.常量被初始化后无法再次修改

类中的常量函数:
1.类中的常量函数的定义 const 需要添加在函数的后面
void show() const
2.类中的常量函数不能《修改》,类中的《所有》数据成员。 (保护了类中的数据成员,更加安全)
3.假设用户想要数据被常量函数修改,那么就在数据前添加 mutable 关键字即可
常量对象:
1.利用const 修饰的对象就是常量对象
2.常量对象,无法修改类中的公共成员
3.常量对象,假设想要修改类中的公共成员,那么必须使用 mutable 说明
4.常量对象,只能调用常量函数。无法调用普通函数
练习: 想办法让常量对象可以修改 类中的公共成员。。mutable 修饰即可
四.C++异常处理(try catch throw)
为什么异常处理???
使用new分配内存时 ,内存空间不够导致无法分配
访问数组元素, 数组下标越界
打开文件,文件不存在
访问指针 , 指针是野指针........................
1 在c语言中,解决异常的方式:
if(fd < 0){
}
利用if语句判断操作是否正确
2.在C++中处理异常的方式:
try(测试 ) catch(捕获异常) throw (抛出异常)
语法:
C++ try{ 用户要执行的语句 } catch(异常类型){ 异常处理代码 } |
3.c和c++中处理异常方式的区别:
c++中的处理异常能力更强, 逻辑上更严谨, 而且系统预定了很多异常的抛出,如new, at等等...
C:面向过程 程序运行->出现错误->解决错误->程序继续执行->出现错写->解决错误->.....
C++: 面向对象 程序的错误是在类中抛出和捕获 不会影响代码的继续执行
程序运行 -> 出现异常1 -> 抛出异常1 -> 程序运行->出现异常2 -> 抛出异常2... -> catch(1){处理}->catch(2){处理}
4.throw 语句:系统不自动抛出异常,需要手动抛出
语法:
C++ throw 表达式; #include <iostream> using namespace std; int main(int argc, char const *argv[]) { string a = "hello"; try{ cout << "12313" << endl; int a = 1000; if(a >= 100){ throw "数值过大"; //手动抛出 } cout << "12313" << endl; } catch(...){ cout << "出现异常,处理中..." << endl; } cout << "world" << endl; return 0; } |
5.异常的类型捕获:
C++ catch(...) ...表示捕获任意类型的异常, 拿不到异常的数据 try{ 测试语句 } catch(int a){ } catch(base a){ } catch(string a){ } catch(...){ //其他异常 } |
6.系统提供的预定义异常类型:
exception类:

C++ catch(exception &e){ cout << "其他异常:" << e.what() <<endl; } //案例: try{ // int *p = new int[0xFFFFFFFFFF]; string a = "abcdeg"; cout << a.at(10000) << endl; } catch(exception &e){ cout << "异常原因:" << e.what() << endl; } |
7.异常的再抛出
当一个函数出现异常的时候, 这个异常如果抛出后未被处理, 会继续抛出, 直到处理为止!!!
C++ #include <iostream> using namespace std; //抛出异常 -- 自己处理 void test(){ try{ throw "我是异常"; } catch(...){ cout << "捕获到异常" << endl; } } void test1(){ //出现了异常 但是没有处理 cout << "test1" << endl; throw "我是test1的异常"; } void test2(){ cout << "test2" << endl; test1(); //接收到了test1 的 异常 } int main(int argc, char const *argv[]) { try{ test2(); } catch(...){ cout << "我来处理" << endl; } return 0; } |
目录
一. 模板函数
二.模板类
1.模板类语法:
2.模板类和模板函数的区别
3.模板类可以作为函数参数进行传递
4.模板类成员函数在类外定义
5.模板类的继承
三.补充:
c++ 中的数据成员属性
类中的静态成员:
类中的静态函数:
类中的const成员
常量成员的作用
类中的常量成员
四.C++异常处理(try catch throw)
1 在c语言中,解决异常的方式:
2.在C++中处理异常的方式:
3.c和c++中处理异常方式的区别:
4.throw 语句:系统不自动抛出异常,需要手动抛出
5.异常的类型捕获:
6.系统提供的预定义异常类型:
7.异常的再抛出