0.目录

1.数组类模板

2.智能指针类模板

3.单例类模板

4.小结

1.数组类模板

模板参数可以是数值型参数(非类型参数):

数值型模板参数的限制:

  • 变量不能作为模板参数
  • 浮点数不能作为模板参数
  • 类对象不能作为模板参数
  • 。。。

本质:

模板参数是在编译阶段被处理的单元,因此,在编译阶段必须准确无误的唯一确定。

1.1 类模板高效率求和

用你觉得最高效的方法求 1+2+3+...+N 的值!

示例——使用模板、递归和特化求和:

#include <iostream>

using namespace std;

template
< int N >
class Sum
{
public:
static const int VALUE = Sum<N-1>::VALUE + N;
}; template
< >
class Sum < 1 >
{
public:
static const int VALUE = 1;
}; int main()
{
cout << "1 + 2 + 3 + ... + 10 = " << Sum<10>::VALUE << endl;
cout << "1 + 2 + 3 + ... + 100 = " << Sum<100>::VALUE << endl; return 0;
}

运行结果为:

[root@bogon Desktop]# g++ test.cpp
[root@bogon Desktop]# ./a.out
1 + 2 + 3 + ... + 10 = 55
1 + 2 + 3 + ... + 100 = 5050

从效率的角度来说,这里的求和是很高效的。既没有加减法,也没有乘除法,也没有函数调用,也没有循环。在输出的时候VALUE是一个常量,常量的值在编译的时候就已经确定了。因此,输出的时候就仅仅是访问一个常量的值。

相加求和是在编译器编译程序的时候完成的,编译完程序之后要求的和就已经确定了,所以在运行的时候就可以直接访问到这个和的值了,而不需要做任何其他运算,因此效率是很高的。

1.2 数组类模板

示例——实现数组类模板:

// Array.h
#ifndef _ARRAY_H_
#define _ARRAY_H_ template
< typename T, int N >
class Array
{
T m_array[N];
public:
int length();
bool set(int index, T value);
bool get(int index, T& value);
T& operator[] (int index);
T operator[] (int index) const;
virtual ~Array();
}; template
< typename T, int N >
int Array<T, N>::length()
{
return N;
} template
< typename T, int N >
bool Array<T, N>::set(int index, T value)
{
bool ret = (0 <= index) && (index < N); if( ret )
{
m_array[index] = value;
} return ret;
} template
< typename T, int N >
bool Array<T, N>::get(int index, T& value)
{
bool ret = (0 <= index) && (index < N); if( ret )
{
value = m_array[index];
} return ret;
} template
< typename T, int N >
T& Array<T, N>::operator[] (int index)
{
return m_array[index];
} template
< typename T, int N >
T Array<T, N>::operator[] (int index) const
{
return m_array[index];
} template
< typename T, int N >
Array<T, N>::~Array()
{
} #endif
// main.cpp
#include <iostream>
#include "Array.h" using namespace std; int main()
{
Array<double, 5> ad; for(int i=0; i<ad.length(); i++)
{
ad[i] = i * i;
} for(int i=0; i<ad.length(); i++)
{
cout << ad[i] << endl;
} return 0;
}

运行结果为:

[root@bogon Desktop]# g++ main.cpp
[root@bogon Desktop]# ./a.out
0
1
4
9
16

1.3 堆数组类模板

示例——实现堆数组类模板(即数组创建在堆上):

// HeapArray.h
#ifndef _HEAPARRAY_H_
#define _HEAPARRAY_H_ template
< typename T >
class HeapArray
{
private:
int m_length;
T* m_pointer; HeapArray(int len);
HeapArray(const HeapArray<T>& obj);
bool construct();
public:
static HeapArray<T>* NewInstance(int length);
int length();
bool get(int index, T& value);
bool set(int index ,T value);
T& operator [] (int index);
T operator [] (int index) const;
HeapArray<T>& self();
~HeapArray();
}; template
< typename T >
HeapArray<T>::HeapArray(int len)
{
m_length = len;
} template
< typename T >
bool HeapArray<T>::construct()
{
m_pointer = new T[m_length]; return m_pointer != NULL;
} template
< typename T >
HeapArray<T>* HeapArray<T>::NewInstance(int length)
{
HeapArray<T>* ret = new HeapArray<T>(length); if( !(ret && ret->construct()) )
{
delete ret;
ret = 0;
} return ret;
} template
< typename T >
int HeapArray<T>::length()
{
return m_length;
} template
< typename T >
bool HeapArray<T>::get(int index, T& value)
{
bool ret = (0 <= index) && (index < length()); if( ret )
{
value = m_pointer[index];
} return ret;
} template
< typename T >
bool HeapArray<T>::set(int index, T value)
{
bool ret = (0 <= index) && (index < length()); if( ret )
{
m_pointer[index] = value;
} return ret;
} template
< typename T >
T& HeapArray<T>::operator [] (int index)
{
return m_pointer[index];
} template
< typename T >
T HeapArray<T>::operator [] (int index) const
{
return m_pointer[index];
} template
< typename T >
HeapArray<T>& HeapArray<T>::self()
{
return *this;
} template
< typename T >
HeapArray<T>::~HeapArray()
{
delete[]m_pointer;
} #endif
// main.cpp
#include <iostream>
#include "HeapArray.h" using namespace std; int main()
{
HeapArray<char>* pai = HeapArray<char>::NewInstance(10); if( pai != NULL )
{
HeapArray<char>& ai = pai->self(); for(int i=0; i<ai.length(); i++)
{
ai[i] = i + 'a';
} for(int i=0; i<ai.length(); i++)
{
cout << ai[i] << endl;
}
} delete pai; return 0;
}

运行结果为:

[root@bogon Desktop]# g++ main.cpp
[root@bogon Desktop]# ./a.out
a
b
c
d
e
f
g
h
i
j

2.智能指针类模板

智能指针的意义:

  • 现代C++开发库中最重要的类模板之一
  • C++中自动内存管理的主要手段
  • 能够很大程度上避开内存相关的问题

STL中的智能指针 auto_ptr:

  • 生命周期结束时,销毁指向的内存空间
  • 不能指向堆数组,只能指向堆对象(变量)
  • 一片堆空间只属于一个智能指针对象
  • 多个智能指针对象不能指向同一片堆空间

2.1 使用智能指针

示例——使用auto_ptr:

#include <iostream>
#include <memory> using namespace std; class Test
{
string m_name;
public:
Test(const char* name)
{
cout << "Hello, " << name << "." << endl; m_name = name;
} void print()
{
cout << "I'm " << m_name << "." << endl;
} ~Test()
{
cout << "Goodbye, " << m_name << "." << endl;
}
}; int main()
{
auto_ptr<Test> pt(new Test("HelloWorld")); cout << "pt = " << pt.get() << endl;
pt->print();
cout << endl; auto_ptr<Test> pt1(pt); cout << "pt = " << pt.get() << endl;
cout << "pt1 = " << pt1.get() << endl;
pt1->print(); return 0;
}

运行结果为:

[root@bogon Desktop]# g++ test.cpp
[root@bogon Desktop]# ./a.out
Hello, HelloWorld.
pt = 0x18ea010
I'm HelloWorld. pt = 0
pt1 = 0x18ea010
I'm HelloWorld.
Goodbye, HelloWorld.

STL中的其它智能指针:

  • shared_ptr——带有引用计数机制,支持多个指针对象指向同一片内存
  • weak_ptr——配合shared_ptr而引入的一种智能指针
  • unique_ptr——一个指针对象指向一片内存空间,不能构造拷贝和赋值

Qt中的智能指针:

  • QPointer

    1. 当其指向的对象被销毁时,它会被自动置空
    2. 析构时不会自动销毁所指向的对象
  • QSharedPointer
    1. 引用计数型智能指针
    2. 可以被自由地拷贝和赋值
    3. 当引用计数为0时才删除指向的对象

2.2 智能指针类模板

示例——创建智能指针类模板:

// SmartPointer.h
#ifndef _SMARTPOINTER_H_
#define _SMARTPOINTER_H_ template
< typename T >
class SmartPointer
{
T* mp;
public:
SmartPointer(T* p = NULL)
{
mp = p;
} SmartPointer(const SmartPointer<T>& obj)
{
mp = obj.mp;
const_cast<SmartPointer<T>&>(obj).mp = NULL;
} SmartPointer<T>& operator = (const SmartPointer<T>& obj)
{
if( this != &obj )
{
delete mp;
mp = obj.mp;
const_cast<SmartPointer<T>&>(obj).mp = NULL;
} return *this;
} T* operator -> ()
{
return mp;
} T& operator * ()
{
return *mp;
} bool isNull()
{
return (mp == NULL);
} T* get()
{
return mp;
} ~SmartPointer()
{
delete mp;
}
}; #endif
// test.cpp
#include <iostream>
#include "SmartPointer.h" using namespace std; class Test
{
string m_name;
public:
Test(const char* name)
{
cout << "Hello, " << name << "." << endl; m_name = name;
} void print()
{
cout << "I'm " << m_name << "." << endl;
} ~Test()
{
cout << "Goodbye, " << m_name << "." << endl;
}
}; int main()
{
SmartPointer<Test> pt(new Test("HelloWorld")); cout << "pt = " << pt.get() << endl;
pt->print();
cout << endl; SmartPointer<Test> pt1(pt); cout << "pt = " << pt.get() << endl;
cout << "pt1 = " << pt1.get() << endl;
pt1->print(); return 0;
}

运行结果为:

[root@bogon Desktop]# g++ test.cpp
[root@bogon Desktop]# ./a.out
Hello, HelloWorld.
pt = 0x20a3010
I'm HelloWorld. pt = 0
pt1 = 0x20a3010
I'm HelloWorld.
Goodbye, HelloWorld.

3.单例类模板

需求的提出:

在架构设计时,某些类在整个系统生命期中最多只能有一个对象存在(Single Instance)。

如何定义一个类,使得这个类最多只能创建一个对象?

要控制类的对象数目,必须对外隐藏构造函数

思路:

  • 将构造函数的访问属性设置为private
  • 定义instance并初始化为NULL
  • 当需要使用对象时,访问instance的值
    1. 空值:创建对象,并用instance标记
    2. 非空值:返回instance标记的对象

3.1 实现单例模式

示例——实现单例模式:

#include <iostream>

using namespace std;

class SObject
{
static SObject* c_instance; // 标识符:当前有没有对象 SObject(const SObject&);
SObject& operator= (const SObject&); SObject() { }
public:
static SObject* GetInstance(); void print()
{
cout << "this = " << this << endl;
}
}; SObject* SObject::c_instance = NULL; SObject* SObject::GetInstance()
{
if( c_instance == NULL )
{
c_instance = new SObject();
} return c_instance;
} int main()
{
SObject* s = SObject::GetInstance();
SObject* s1 = SObject::GetInstance();
SObject* s2 = SObject::GetInstance(); s->print();
s1->print();
s2->print(); return 0;
}

运行结果为:

[root@bogon Desktop]# g++ test.cpp
[root@bogon Desktop]# ./a.out
this = 0x17cf010
this = 0x17cf010
this = 0x17cf010

存在的问题——需要使用单例模式时:

  • 必须定义静态成员变量c_instance
  • 必须定义静态成员函数GetInstance()

解决方案:

将单例模式相关的代码抽取出来,开发单例类模板。当需要单例类时,直接使用单例类模板。

3.2 单例类模板

示例——创建单例类模板:

// Singleton.h
#ifndef _SINGLETON_H_
#define _SINGLETON_H_ template
< typename T >
class Singleton
{
static T* c_instance;
public:
static T* GetInstance();
}; template
< typename T >
T* Singleton<T>::c_instance = NULL; template
< typename T >
T* Singleton<T>::GetInstance()
{
if( c_instance == NULL )
{
c_instance = new T();
} return c_instance;
} #endif
// test.cpp
#include <iostream>
#include "Singleton.h" using namespace std; class SObject
{
friend class Singleton<SObject>; // 当前类需要使用单例模式 SObject(const SObject&);
SObject& operator= (const SObject&); SObject() { }
public:
void print()
{
cout << "this = " << this << endl;
}
}; int main()
{
SObject* s = Singleton<SObject>::GetInstance();
SObject* s1 = Singleton<SObject>::GetInstance();
SObject* s2 = Singleton<SObject>::GetInstance(); s->print();
s1->print();
s2->print(); return 0;
}

运行结果为:

[root@bogon Desktop]# g++ test.cpp
[root@bogon Desktop]# ./a.out
this = 0x1bfd010
this = 0x1bfd010
this = 0x1bfd010

4.小结

  • 模板参数可以是数值型参数
  • 数值型模板参数必须在编译期间唯一确定
  • 数组类模板是基于数值型模板参数实现的
  • 数组类模板是简易的线性表数据结构
  • 智能指针C++中自动内存管理的主要手段
  • 智能指针在各种平台上都有不同的表现形式
  • 智能指针能够尽可能的避开内存相关的问题
  • STL和Qt中都提供了对智能指针的支持
  • 单例模式是开发中最常用的设计模式之一
  • 单例模式的应用使得一个类最多只有一个对象
  • 可以将单例模式相关的代码抽象成类模板
  • 需要使用单例模式的类直接使用单例类模板

C++解析(27):数组、智能指针与单例类模板的更多相关文章

  1. 28.C++- 单例类模板(详解)

    单例类 描述 指在整个系统生命期中,一个类最多只能有一个实例(instance)存在,使得该实例的唯一性(实例是指一个对象指针)  , 比如:统计在线人数 在单例类里,又分为了懒汉式和饿汉式,它们的区 ...

  2. C++之单例类模板

    单例类模板:一个类只能有一个对象,比如超市收银系统中清点物品的仪器只有一个 设计思路: 1.构造函数,拷贝构造函数必须设计为private,防止自己生成新的对象 2.且类的指针要设计为static类型 ...

  3. C++中的单例类模板

    1,本节课讲述单例类模式,实现并抽取相关代码实现单例类模板,在以后开发工作 中,如果想要使用单例模式,那么直接使用今天开发的单例类模板就可以: 2,需求的提出: 1,在架构设计时,某些类在整个系统生命 ...

  4. c++ 中的单例类模板的实现方法

    1.什么是单例模式 在架构设计时,某些类在整个系统生命周期中最多只能有一个对象存在 ( Single Instance ).如超市收银系统,其外观主要由显示器(1个).扫描枪(1个).收款箱(1个)组 ...

  5. 27.C++- 智能指针

    智能指针 在C++库中最重要的类模板之一 智能指针实际上是将指针封装在一个类里,通过对象来管理指针. STL中的智能指针auto_ptr 头文件: <memory> 生命周期结束时,自动摧 ...

  6. Spring源码解析之八finishBeanFactoryInitialization方法即初始化单例bean

    Spring源码解析之八finishBeanFactoryInitialization方法即初始化单例bean 七千字长文深刻解读,Spirng中是如何初始化单例bean的,和面试中最常问的Sprin ...

  7. [转]单例模式——C++实现自动释放单例类的实例

    [转]单例模式——C++实现自动释放单例类的实例 http://www.cnblogs.com/wxxweb/archive/2011/04/15/2017088.html http://blog.s ...

  8. (七)boost库之单例类

    (七)boost库之单例类 一.boost.serialzation的单件实现 单例模式是一种常用的软件设计模式.在它的核心结构中只包含一个被称为单例类的特殊类.通过单例模式可以保证系统中一个类只有一 ...

  9. Hibernate 系列教程1-枚举单例类

    你还在为不知道怎样正确使用Hibernate而纠结吗 你还在为不知道怎样配置映射文件而郁闷吗 枚举单例(Enum Singleton) 是实现单例模式的一种方式而已,不过写法简单,创建枚举默认也是线程 ...

随机推荐

  1. 【LOJ121】「离线可过」动态图连通性

    [LOJ121]「离线可过」动态图连通性 题面 LOJ 题解 线段树分治的经典应用 可以发现每个边出现的时间是一个区间 而我们每个询问是一个点 所以我们将所有边的区间打到一颗线段树上面去 询问每个叶子 ...

  2. 读懂UML类图

    平时阅读一些远吗分析类文章或是设计应用架构时没少与UML类图打交道.实际上,UML类图中最常用到的元素五分钟就能掌握,下面赶紧来一起认识一下它吧: 一.类的属性的表示方式 在UML类图中,类使用包含类 ...

  3. Python运维三十六式:用Python写一个简单的监控系统

    市面上有很多开源的监控系统:Cacti.Nagios.Zabbix.感觉都不符合我的需求,为什么不自己做一个呢? 用Python两个小时徒手撸了一个简易的监控系统,给大家分享一下,希望能对大家有所启发 ...

  4. Android线程管理(一)——线程通信

    线程通信.ActivityThread及Thread类是理解Android线程管理的关键. 线程,作为CPU调度资源的基本单位,在Android等针对嵌入式设备的操作系统中,有着非常重要和基础的作用. ...

  5. javaweb(十五)——JSP基础语法

    任何语言都有自己的语法,JAVA中有,JSP虽然是在JAVA上的一种应用,但是依然有其自己扩充的语法,而且在JSP中,所有的JAVA语句都可以使用. 一.JSP模版元素 JSP页面中的HTML内容称之 ...

  6. HCIE理论-IPV6

    ipv4与ipv6的对比 IPv4 :32 bit 点分十进制 192.168.1.1 2^32=42.9亿 ipv4地址不足IPv6 :128 bit 十六进制 2^128 冒号分十六进制ipv4 ...

  7. python编码和小数据池

    python_day_6 一. 回顾上周所有内容一. python基础 Python是一门解释型. 弱类型语言 print("内容", "内容", end=&q ...

  8. 180718-jar包执行传参使用小结

    jar包执行时传参的使用姿势 虽说我们现在大多不太直接使用jar包运行方式,目前比较主流的是将自己的服务丢在某个容器中(如tomcat,jetty等)运行,比如我之前所属的电商公司,就是将项目打包为w ...

  9. Unity3D之AR开发(二)

    上一篇给大家介绍了高通AR的使用,接下来给大家分享一下EasyAR EasyAR引擎简介 EasyAR是做好用的且免费的增强现实(Augmented Reality)引擎,EasyAR为Unity开发 ...

  10. python2和python3同时存在如何安装和使用pip

    linux下 如果没有pip则需要安装pip python2安装pip sudo apt install python-pip1如果是python3,则如下: sudo apt install pyt ...