泛化编程 day02
Posted 达少Rising
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了泛化编程 day02相关的知识,希望对你有一定的参考价值。
回顾:
泛化编程 day01
四、模板技巧
1、模板型类模板成员
- 1)模板型成员变量
类模板的成员变量
,但类型是由一个类模板实例化的未知类
,那么它就是模板型成员变量。
eg:
template<class T>class Array{...};
template<class D>class Sum{
public:
Array<D> m_arr[10];//模板型成员变量
};
eg:01membervar.cpp
#include <iostream>
using namespace std;
template<class T>class Arrary
{
public:
T& operator[](size_t i){
return m_arr[i];
}
private:
T m_arr[10];
};
template<class D>class Sum
{
public:
Sum(Arrary<D> const& s):m_s(s){}
D sum(){
D d=0;
for(size_t i=0; i<10; i++){
d += m_s[i];
}
return d;
}
private:
Arrary<D> m_s;//模板型成員變量
};
int main(void)
{
Arrary<int> a;
for(size_t i=0; i<10; i++){
a[i] = i+1;
}
Sum<int> s(a);
cout << s.sum() << endl;
return 0;
}
- 2)模板型成员函数(
成员函数模板
)
类模板的成员函数模板
。
eg:
template<class T>class CMath{
public:
template<class D>void foo(){...}
};
//如果在类外实现:
template<class T>
template<class D>void CMath<T>::foo(){...}
eg:02memberfunc.cpp
#include <iostream>
using namespace std;
template<class T>class CMath
{
public:
template<class D>void foo(){
cout << "CMath<T>::foo()" << endl;
}
};
int main(void)
{
CMath<int> m;
m.foo<double>();
return 0;
}
- 3)模板成员类型
类模板中嵌套的类模板
eg:
template<class X>class A{
public:
template<class Y>class B{...};
};
eg:03membertype.cpp
#include <iostream>
using namespace std;
template<class X>class A
{
public:
template<class Y>class B
{
public:
template<class Z>class C;
};
};
//在类外实现
template<class X>
template<class Y>
template<class Z>
class A<X>::B<Y>::C{
public:
template<class M>void foo(){
cout << "A<X>::B<Y>::C<Z>::foo()" << endl;
}
};
int main(void)
{
A<int>::B<double>::C<string> c;
c.foo<float>();
return 0;
}
2、模板型模板参数
- 类模板的模板形参也可以是
类模板
,可以有缺省值
eg:
template<class T>class Array(){...};
template<template<class D>class C=Array>
class Sum{
...
};
eg:04templateArgs.cpp
#include <iostream>
using namespace std;
template<class T>class Arrary
{
public:
T& operator[](size_t i){
return m_arr[i];
}
private:
T m_arr[10];
};
template<class D, template<class R>class C>class Sum
{
public:
Sum(C<D> const& s):m_s(s){}
D sum(){
D d=0;
for(size_t i=0; i<10; i++){
d += m_s[i];
}
return d;
}
private:
C<D> m_s;//Arrary<D> m_s;
};
int main(void)
{
Arrary<int> a;
for(size_t i=0; i<10; i++)
a[i] = i+1;
Sum<int, Arrary> s(a);
cout << s.sum() << endl;
return 0;
}
3、嵌套依赖(这里的模板既是类模板也可以是函数模板)
- 1)问题:由于模板经过两次编译,在第一次编译模板代码时,
模板的类型形参的具体类型尚未明确
,编译器将把模板类型形参的嵌套类型理解为某个未知类型的静态成员变量
,因此编译器看到使用这样的标识符
声明的变量是会报告错误,这就是嵌套依赖。 - 2)解决方法:在类型形参的前面增加一个typename标识符,意在告诉编译器其后是一个
类模板的嵌套使用
。
eg:05typename.cpp
#include <iostream>
using namespace std;
class A
{
public:
class B{
public:
void foo(){
cout << "A::B::foo()" << endl;
}
};
};
template<class T>void Func()
{
//T::B b;//錯誤的版本,解析如下
//嵌套依賴:看到T::B編譯器認爲B是未知類型T的靜態成員變量,
//但是T::B b後不能理解就會報錯
typename T::B b;//改正的版本
b.foo();
}
int main(void)
{
Func<A>();
return 0;
}
4、依赖模板参数访问成员函数模板
- 1)问题:利用
未知类
定义对象来访问成员函数模板
时,编译器在第一次编译时无法解析成员函数模板的类型参数列表的<>
而报告编译错误。 - 2)解决办法:在成员函数模板之前增加template关键字,意在告诉编译器其后面是一个函数模板实例,编译器就可以正确理解
<>
了。
eg:06template.cpp
#include <iostream>
using namespace std;
class A
{
public:
template<class T>void foo(){
cout << "A::foo<T>()" << endl;
}
};
template<class D>void Func()
{
D d;
//d.foo<int>();//第一次編譯錯誤,用未知類型調用成員函數模板
//d.foo();//第二次編譯錯誤
//解決辦法
d.template foo<int>();
return;
}
int main(void)
{
Func<A>();
return 0;
}
5、子类模板访问基类模板
- 1)问题:在子类模板中访问基类模板的成员,编译器在
第一次
编译子类模板时,通常会认为基类类型不确定(未知类)
,所以只在子类模板或全局域中搜索使用的标识符号。 - 2)解决方法:在子类模板中可以通过使用作用域限定符或显式使用this指针。
eg:07this.cpp
#include <iostream>
using namespace std;
template<class T>class Base
{
public:
void foo(void){
cout << "Base<T>::foo()" << endl;
}
int m_i;
};
template<class T, class D>class Derived:public Base<T>
{
public:
void bar(){
/*
//以下代碼會報錯,子類模板訪問基類模板的成員
m_i = 0;
foo();
*/
//解決辦法1
Base<T>::m_i = 0;
Base<T>::foo();
//解決辦法2
//this->m_i = 0;
//this->foo();
}
};
int main(void)
{
Derived<int, int> d;
d.bar();
return 0;
}
6、零值初始化
- 1)
基本类型不存在缺省构造函数
,未被初始化的局部变量都具有一个不确定的值
eg:int a;//不确定 - 2)
类类型由于存在缺省构造函数
,未被初始化的情况下可以有一个确定的缺省初始化状态
eg:Integer a;//值确定 - 3)显式构造函数:如果希望模板中,所有类型参数的变量,无论是类类型还是基本类型都以缺省方式获得初始化,就必须对其尽进行显式的缺省构造 T()
注: 对于类模板可以在其缺省构造函数的初始化表
中对每个成员变量显式地初始化,无论是类类型还是基本类型。
eg:
#include <iostream>
using namespace std;
class Integer
{
public:
Integer():m_i(0){}
friend ostream& operator<<(ostream& os, Integer const& i){
return os << i.m_i;
}
private:
int m_i;
};
template<class T>class CMath
{
public:
//**注:** 对于类模板可以在其缺省构造函数的`初始化表`中对每个成员变量显式地初始化,无论是类类型还是基本类型
CMath():m_t(T())(){}
private:
T m_t;
};
template<class T>void Func()
{
//聲明但沒有定義,就是沒有給定初值
//所以基本類型的值不確定,類類型會調用缺省構造
//T t;
//解決辦法
T t = T();
cout << "t=" << t << endl;
}
int main(void)
{
Func<int>();//基本類型
Func<Integer>();//類類型
return 0;
}
7、类模板中的成员虚函数
- 1)
类模板
中的普通成员函数可以是
虚函数(即可以为类模板定义成员虚函数),和普通函数的成员函数一样,类模板的成员虚函数也可以表现出多态性
。 - 2)
类模板
中的成员函数模板不可以是
虚函数:根据成员虚函数的多态机制,需要一个虚函数表(表中保存成员虚函数的入口地址),而这个表是编译器在实例化类模板时就产生
,类的成员函数模板的实例化(即产生真正的函数实体)需要编译器处理完调用后才会完成,这时才出现成员虚函数地址。所以类模板
中的成员函数模板不可以是
虚函数。 - 总结:成员函数模板的延迟编译阻碍了虚函数表的静态构建。
eg:09virtual.cpp
#include <iostream>
using namespace std;
template<class T>class Base
{
public:
virtual void foo(void){
cout << "Base<T>::foo()" << endl;
}
};
template<class T, class D>class Derived:public Base<T>
{
public:
virtual void foo(void){
cout << "Derived<T, D>::foo()" << endl;
}
//成員函數模板不能是虛函數
//virtual template<class R>void bar(void){}
//成员函数模板的延迟编译阻碍了虚函数表的静态构建
};
int main(void)
{
Base<int> b;
b.foo();
Derived<int, int> d;
Base<int>* p = &d;
p->foo();
return 0;
}
五、自制基本链表容器
1、实现功能
- 缺省构造/拷贝构造/析构函数/输入流缓冲重载
- push_back/pop_back——尾部添加/删除节点
- push_front/pop_front——首部添加/删除节点
- front/back——获取首部/尾部的元素
- clear/empty——清空链表/判空链表
- size——获取链表的大小(节点的个数)
#include <iostream>
#include <stdexcept>
using namespace std;
template<class T>class list
{
public:
//
//缺省構造
//
list():m_head(NULL), m_tail(NULL){}
//
//拷貝構造(深拷貝)
//
list(list const& that):m_head(NULL), m_tail(NULL){
for(node* pnode=that.m_head; pnode; pnode=pnode->m_next){
push_back(pnode->m_data);
}
}
//
//析構函數
//
~list(){
clear();
}
//
//鏈表判空
//
bool empty(){
return m_head==NULL && m_tail==NULL;
}
//
//在鏈表的頭部添加節點
//
void push_front(T const& data){
m_head = new node(data, NULL, m_head);
if(m_head->m_next){
m_head->m_next->m_prev = m_head;
}
else{
m_tail = m_head;
}
}
//
//刪除鏈表頭節點
//
void pop_front(){
if(empty())
return;
node* pnode = m_head->m_next;
delete(m_head);
if(pnode){
pnode->m_prev = NULL;
}
else{
m_tail = NULL;
}
m_head = pnode;
}
//
//獲取鏈表頭節點數據
//
T& front(){
if(empty())
throw underflow_error("front():null node");
return m_head->m_data;
}
T const& front()const{
return const_cast<list*>(this)->front();
}
//
//在鏈表的尾部添加節點
//
void push_back(T const& data){
m_tail = new node(data, m_tail, NULL);
if(m_tail->m_prev)
m_tail->m_prev->m_next = m_tail;
else
m_head = m_tail;
}
//
//刪除鏈表的尾節點
void pop_back(){
if(empty())
return;
node* pnode = m_tail泛化编程 day01