- 一 类模板
- (1)概念
- (2)模板类的继承
- (3)模板类的声明
- 二 成员模板
- 2.1 为什么要使用成员模板
- 2.2 成员模板的实现
- 三 关键词-typename
- 3.1 内嵌依赖类型名
- 3.2 实例
- 四 using 给模板起别名
- 五 实例化
- 5.1 #pragma once
- 5.2 隐式实例化
- 5.3 显示实例化
- 5.3.1 函数模板的显示实例化
- 5.3.2 类模板的显示实例化
- 5.4 模板全特化和偏特化
- 5.4.1 为什么要模板特化?
- (1) 类模板的全特化
- (2) 类模板的偏特化
- 六 内存管理
- 6.1 c++内存管理
- 6.2 内存分析诊断工具 valgrind
- 6.3 如何避免内存泄漏
- 6.4 c++为什么没有提供GC机制(垃圾回收机制)
- 6.5 智能指针
- 6.5.1 作用
- 6.5.2 分类
- 6.5.3 share_ptr
类模板中定义的函数参数类型或者属性等数据类型可以参数化。
templateclass 类型{ //... }
#include(2)模板类的继承using namespace std; template class Test { private: T a; U b; public: Test(T a, U b) { this->a = a; this->b = b; } void show() { cout << a << " " << b << endl; } }; int main(int argc,char*argv[]) { //Test t(1, 'a'); Test t(1, 'a'); //类模板创建一定要显示调用 t.show(); return 0; }
#include(3)模板类的声明using namespace std; template class Parent { protected: T a; public: Parent(T a) { this->a = a; } void show() { cout << a << endl; } }; class Child:public Parent //模板类派生普通类,继承的同时对基类实例化 { public: Child(int a) :Parent(a) { } void show() { cout << a << endl; } }; template class Child2 :public Parent //模板类派生模板类,继承的同时不需要对parent实例化 { private: U b; public: Child2(T a, U b) :Parent (a) { this->b = b; } void show() { cout << this->a << " " << this->b << endl; } }; int main(int argc,char*argv[]) { Child c1(1); c1.show(); Child2 c2(1, 1.11); c2.show(); return 0; }
#includeusing namespace std; template class Test { public: Test(T a); void show(); ~Test(); protected: private: T a; }; template Test ::Test(T a) //Test 表示Test是模板类,不是普通类 { this->a = a; } template void Test ::show() { cout << a << endl; } template Test ::~Test() { } int main(int argc,char*argv[]) { return 0; }
(4) 模板类中的static
#include二 成员模板 2.1 为什么要使用成员模板using namespace std; template class Test { public: Test(T a); void show(); ~Test(); protected: private: T a; public: static int count; }; template int Test ::count = 0; template Test ::Test(T a) //Test 表示Test是模板类,不是普通类 { this->a = a; count++; } template void Test ::show() { cout << a << endl; } template Test ::~Test() { } int main(int argc,char*argv[]) { Test t1(1); Test t2(1); Test t3(1); Test t4(1); Test t5(1); Test t6('a'); Test t7('a'); Test t8('a'); cout << Test ::count << endl; cout << Test ::count << endl; return 0; }
#include2.2 成员模板的实现using namespace std; template class Test { public: T m_a; public: void print(const Test &a) { cout << a.m_a << endl; } }; int main(int argc,char *argv[]) { Test a; a.m_a = 1; Test b; b.m_a = 1.123; a.print(a); a.print(b); return 0; }
#include三 关键词-typename 3.1 内嵌依赖类型名using namespace std; //template template class Test { public: T m_a; public: template void print(const Test &a) { cout << a.m_a << endl; } }; int main(int argc,char *argv[]) { Test a; a.m_a = 1; Test b; b.m_a = 1.123; a.print(a); a.print(b); return 0; }
内嵌:是指在类的内部定义的 依赖:依赖于摸一个模板参数 类型名:最终要指出的这个类型名3.2 实例
#include四 using 给模板起别名using namespace std; //template template class Test { public: T m_a; typedef T* PT; //实际上就是一个内嵌依赖类型名 //static int PT; public: template void print(const Test &a) { cout << a.m_a << endl; } }; int main(int argc,char *argv[]) { int num = 100; //typename Test ::PT p = # Test ::PT p = # return 0; }
#include五 实例化 5.1 #pragma onceusing namespace std; //template template class Test { public: T m_a; typedef T* PT; //实际上就是一个内嵌依赖类型名 //static int PT; public: }; template using MyA = Test ; //将两个参数降为一个参数 using s32 = int; using P_func = void(*)(int, int); int main(int argc,char *argv[]) { Test a; MyA a2; return 0; }
1、ifndef方法是c/c++的标准支持,比较常用的方式
#pragma once一般由编译器提供保证,功能是保证同一个文件不会被包含多次
visual studio 2017之后的版本新建头文件都会自带#pragma once
2、兼容性:#pragma once产生于ifndef之后,ifndef不受任何编译器的限制,而#pragma once方法有些编译器不支持(较老的编译器(gcc3.4之前的不支持)),兼容性不够好,
3、ifndef可以针对文件中的一部分代码,而#pragma once只针对整个文件
4、ifndef 更加灵活,兼容性好,#pragma once操作简单,效率更高。
5.2 隐式实例化
隐式实例化是指在函数调用的时候,如果没有发现与之相匹配的函数存在,编译器会寻找同名的函数模板,如果可以成功进行参数的推演,就对函数模板实例化。 类模板同上。5.3 显示实例化
显示实例化:外部实例化,在不发生函数调用的时候将函数模板实例化 类模板同上。5.3.1 函数模板的显示实例化
template [返回值类型] [函数名]<实际类型列表>(函数参数列表) template void func5.3.2 类模板的显示实例化(const int&);
template class Test; 作用:减少隐式实例化实例多个函数和类的开销,只实例化一次(不同编译器处理机制可能不同)
#pragma once #include#include #include using namespace std; template void print(const T &t) { cout << t << endl; } template > class Stack { public: Stack() { top = -1; } void push(T num) { data.push_back(num); } void pop() { //return data.pop_back(); } int top; CONT data; //vector data; };
#include "template.h" template void print(const int &t); //显示实例化,只实例化一次 template class Stack >; void Func() { print(5); print("hello"); print(10); Stack s; Stack s1; }
#include "template.h" extern void Func(); template void print5.4 模板全特化和偏特化 5.4.1 为什么要模板特化?(const int &t); //显示实例化,只实例化一次 int main(void) { print(5); print("hello"); print(10); Stack s; Stack s1; Func(); }
因为编译器认为,对于特定的类型,如果你能对某一个功能更好的实现,那么就该听你的 模板实例化时会优先匹配“模板参数”最符合那个特化的版本 模板特化的前提已要求模板的泛化。(1) 类模板的全特化
#include(2) 类模板的偏特化#include using namespace std; class A { public: A() { } int m_a; }; template class Test { public: T m_a; U m_b; public: void print() { cout << m_a << endl; cout << m_b << endl; } }; //模板特化的作用:处理一些模板处理不了或者处理不好的数据和方法,需要将这些类型特例化,按照特例化的方法处理 //类的全特化:全部类型全部指定 template<> class Test { public: A m_a; string m_b; public: void print() { cout << "class Test" << endl; cout << m_a.m_a << endl; cout << m_b << endl; } }; int main(void) { Test a; a.m_a = 1; a.m_b = "helloworld"; a.print(); A tb; Test s1; s1.m_a = tb; s1.m_b = "world"; s1.print(); return 0; }
模板参数数量偏特化
#include#include using namespace std; class A { public: A() { } int m_a; }; template class Test { public: T m_a; U m_b; public: void print() { cout << m_a << endl; cout << m_b << endl; } }; //通过减少类模板参数,实现类模板的偏特化 template class Test { public: T m_a; string m_b; public: void print() { cout << "class Test " << endl; cout << m_a << endl; cout <<"name:"< a; a.m_a = 1; a.m_b = "helloworld"; a.print(); return 0; }
(3)类模板参数范围偏特化
int --->const int T -->T* T--->T&
#include六 内存管理 6.1 c++内存管理#include using namespace std; class A { public: A() { } int m_a; }; template //可通过将其改为const,指针,引用等降低其范围 class Test { public: T m_a; U m_b; public: void print() { cout << m_a << endl; cout << m_b << endl; } }; //通过减少类模板参数,实现类模板的偏特化 template class Test { public: T m_a; U m_b; public: void print() { cout << "class Test " << endl; } }; int main(void) { Test a1; a1.print(); return 0; }
大多数问题都是由于内存泄漏导致的。6.2 内存分析诊断工具 valgrind
sudo apt-get update sudo apt-get install -f sudo apt-get intall valgrind
使用 valgrind:
6.3 如何避免内存泄漏new/delete的成对使用 new[]/delete[]成对出现 人为的控制new/delete的问题,无法杜绝内存泄漏6.4 c++为什么没有提供GC机制(垃圾回收机制)
没有共同基类:c++是从c语言发展而来,允许直接操作指针,允许将一个类型转换位另一个类型 对于一个指针无法知道它真正指向的类型,而java和c#都有一个共同的基类。 系统开销:GC机制所带来的系统开销,违反了c++的设计哲学--》不为不必要的功能支持代价,不符合c++高效的特性,不符合底层工作的要求。 消耗内存:c++产生的年代内存比较小 替代方法:c++有析构函数,智能指针,引用计数器等去管理资源的释放。6.5 智能指针 6.5.1 作用
帮助开发者动态的开辟和释放申请的空间,能有效的防止内存泄漏。6.5.2 分类
分类:
auto_ptr(c++98): 被c++11智能指针替代,不再使用
unique_ptr(c++) 独占指针
share_ptr(c++):共享指针
weak_ptr(c++):弱指针
int *p:裸指针
6.5.3 share_ptr
共享式指针:
多个指针可以同时指向一个对象(共享所有权,协同工作) 当最后一个指针被销毁或者指向其它对象时,这个对象会被释放
工作原理:引用计数增加/减少(原子操作)
引用计数增加:
用一个智能指针初始化另一个智能指针
函数传参:传递一个智能指针
函数返回值:返回一个智能指针
引用计数减少:
给智能指针赋予新值,指向一个新对象
局部的智能指针离开其作用域。
定义:
share_ptr<指向的类型> 智能指针变量名
#include暑期编程PK赛 得CSDN机械键盘等精美礼品!#include #include using namespace std; class A { public: A() { cout << "A的无参构造" << endl; } A(int n) { m_a = n; cout << "A的有参构造" << endl; } int m_a; ~A() { cout << "A的析构函数" << endl; } }; shared_ptr test() { shared_ptr temp(new A); return temp; } void Func(shared_ptr temp) { cout << temp->m_a << endl; } int main(void) { //int *p = new int(5); //p是裸指针 //shared_ptr p = new int(5); //初始化:调用类型转换构造函数 explicit shared_ptr p(new int(5)); cout << *p << endl; shared_ptr s(new string("helloworld")); cout << *s << endl; int num = 100; //shared_ptr p2(&num); //智能指针常用于堆空间,指向栈空间的时候,会导致内存释放两次 //A *pa = new A(100); //delete pa; shared_ptr pa(new A); shared_ptr res = test(); Func(pa); shared_ptr pa2(pa); return 0; }



