STL(3)
泛型和多态
泛型其实也是一种多态.
多态的好处:可以有一个统一的接口
多态分为两种:
动态多态
- 在运行期间, 通过抽象的方式, 使用父类指针对象来操作子类对象.
- 是基于面向对象所实现的.
- 通过
纯虚函数来规定统一的接口,必须强制实现 - 代码整体结构更加好, 调试略难, 相对于静态多态运行速度较慢.
静态多态
- 在编译期间完成的多态.
- 是基于泛型实现的.
- 泛型中规定了一些接口, 如果要进行使用, 就必须实现那些接口.
接口的实现是非强制性的- 它更加难调试, 但是运行速度快.
泛型编程小技巧
在使用VS进行泛型编程的时候, 比如如下代码:
#include <vector>
namespace Hades
{
template <typename T, typename CON = std::vector<T> >
class HadesStack
{
public:
void PushBack(const T& ele)
{
c_.push_back(ele);
}
private:
CON c_; // 使用的容器
}
}
在我们进行编程的时候, 由于VS不知道我们使用的是什么类型, 所以无法进行自动提示.
这时, 我们将 CON c_ 先注释掉, 改成 std:vector\<T\> c_ 就可以自动提示代码了.
等我们编写完成后, 一定要记得将我们注释掉的 CON c_ 改回来.
成员模板
template<typename T>
class HadesType
{
private:
public:
T data_;
HadesType(const T data) : data_(data) {}
void Assign(HadesType other)
{
// 不考虑浅拷贝
data_ = other.data_;
}
}
int main()
{
HadesType<int> intType(1);
HadesType<double> doubleType(2.01);
intType.Assign(doubleType); // 报错, 类型不匹配
return 0;
}
解析, 为什么会不行呢?
因为我们的模板, 会经过2次编译.
首先, 我们的HadesType完全没有语法错误.
然后, 在编译期间, 会生成两个完全不同的类型.
当我们在使用Assign的时候, 我们的类型发生了变化.
相当于, HadesTypeInt.Assign(HadesTypeDouble);
这样当然是错误的, 因为我们要 HadesTypeInt.Assign(HadesTypeInt);解决办法:
我们这种操作是很多的, 所以我们需要想办法进行实现.
// 我们将Assign改造一下
template<typename X>
void Assign(X other)
{
// 不考虑浅拷贝
data_ = other.data_;
}现在, 我们就可以进行赋值操作了.
如果我们要将方法和声明分离, 则写成如下模式:
void Assign(HadesType other); // 类中的声明
// 分离实现的写法
template <typename T> // 类模板
template <typename X> // 成员模板
// 类名 // X: 参数类型
void HadesType<T>::Assign(X other)
{
// ....
}注意, 我们的两个 template 缺一不可, 并且
不可写到一起
但是, 当我们的 T data_ 为 private 的时候, 我们就不能通过这种方法来进行了.
因为我们的 data_ 在类的外部依然无法访问.
一定要记住, 我们的模板编程, 所看到的类不是我们原来认识的那个类
那么, 我们在 T data_ 私有的时候, 应该怎么解决呢?
// 在我们已经修改的基础上, 我们再新增一个函数
const T& GetData() const
{
return data_;
}这样, 我们就完美解决了我们 Assign 的问题了.
成员模板可以在任何一个类中出现
class Demo
{
public:
template <typename T> // 成员模板
const T& GetVal(const T& val)
{
return val;
}
}
此时, 如果我们需要声明和实现分离的话, 应该这么写
class Demo
{
public:
template <typename T> // 成员模板
const T& GetVal(const T& val);
};
template <typename T> // 成员模板
const T& Demo::GetVal(const T& val)
{
return val;
}注意, 我们的 Demo 是没有泛型的.
类的全特化
全特化的例子:
#include <iostream>
template <typename T>
class Array
{
private:
T data_;
public:
Array()
{
std::cout << "Array<T>...." << std::endl;
}
~Array()
{
std::cout << "~Array<T>...." << std::endl;
}
const T& GetValue() const
{
return data_;
}
};
// 类的全特化
template <>
class Array<int*>
{
private:
int* data_;
public:
Array()
{
data_ = new int;
std::cout << "Array<int*>...." << std::endl;
}
~Array()
{
delete data_;
std::cout << "~Array<int*>...." << std::endl;
}
};
int main()
{
Array<int> intArr;
Array<int*> intpArr;
return 0;
}执行结果: 
接下来, 我们调用一下 GetValue 函数:
int main()
{
Array<int> intArr;
Array<int*> intpArr;
// 编译错误, Array<int*>中没有这个函数.
std::cout << intpArr.GetValue() << std::endl;
return 0;
}
全特化的类与我们的模板类没有任何关系, 实现的方法 _可以不相同_.
类的全特化并 不是继承
如果我们想调用 intpArr.GetValue(), 我们需要在 Array<int*> 中进行函数的实现.
我们对模板类进行了全特化后, 模板类就不会在编译时进行生成相应的类
特化的类是一个全新的类, 需要的任何功能都需要自己来实现
类的偏特化
偏特化的例子:
#include <iostream>
template <typename T>
class Array
{
private:
T data_;
public:
Array()
{
std::cout << "Array<T>...." << std::endl;
}
~Array()
{
std::cout << "~Array<T>...." << std::endl;
}
const T& GetValue() const
{
return data_;
}
};
// 类的偏特化
template <>
Array<int*>::Array()
{
data_ = new int;
std::cout << "Array<int*>...." << std::endl;
}
// 类的偏特化
template <>
Array<int*>::~Array()
{
delete data_;
std::cout << "~Array<int*>...." << std::endl;
}
int main()
{
Array<int> intArr;
Array<int*> intpArr;
return 0;
}执行结果: 
接下来, 我们调用一下 GetValue 函数:
int main()
{
Array<int> intArr;
Array<int*> intpArr;
// OK, 成功打印
std::cout << intpArr.GetValue() << std::endl;
return 0;
}
执行结果: 
类的偏特化是 _只对当前模板类中的某些特定的类中的某些方法的特化_, 进行有意识的特化
偏特化 特化的是一个方法_, _其他的代码还是由编译器来生成
偏特化的方法, 编译器 不会 进行生成
多模板参数的偏特化
暂略....
模板类的继承
- 一个普通的类可以继承一个模板类.
- 继承时必须制定继承的类的类型
- 不推荐普通类继承自模板类
- 一般都是用模板类继承模板类
template<typename T>
class Base
{
};
class Demo : public Base<int>
{
};
template<typename T>
class Child : public Base<T>
{
};
单例模式
通过包装器的方式, 使用模板类编写一个单例模式.
#include <iostream>
using namespace std;
template<typename T>
class Singleton // 单例模式的模板类
{
public:
static T& GetInstance()
{
if(!pInstance)
{
pInstance = new T;
}
return *pInstance;
}
private:
Singleton();
static T* pInstance;
};
template<typename T>
T* Singleton<T>::pInstance = nullptr;
class Demo
{
public:
void Dump()
{
cout << "Dump!!!!" << endl;
}
}
int main()
{
Singleton<Demo>::GetInstance().Dump();
return 0;
}
未完待续...
如有错误,请提出指正!谢谢.
本文由 花心胡萝卜 创作,采用 知识共享署名4.0 国际许可协议进行许可
本站文章除注明转载/出处外,均为本站原创或翻译,转载前请务必署名
最后编辑时间为: 2017-03-16 at 08:00 am