泛型编程是从一个抽象层面描述一种类型的算法,不管容器类型是什么,是一种不同于OOP的角度来抽象具体算法
C++用模板来实现泛型编程,模板分为函数模板和类模板
template<class/typename T> //告诉编译器遇到T不要报错
mySwap(T &a, T &b) //类型参数化,在使用时会进行自动类型推导,将a和b的类型传给T
mySwap<int>(a, b) //显式指定类型
在使用函数模板时,一定要让编译器知道T是什么类型,否则无法使用
普通函数可以进行隐式类型转换(显示表示)
函数模板不可以
当普通函数对函数模板进行了函数重载时,优先调用普通函数,如果普通函数出错,则出错,不会再去调用函数模板
如果需要强制调用函数模板,可以加 <> 来调用
如果函数模板可以产生更好的匹配,优先调用函数模板
模板不能解决所有的类型,可以使用第三代具体化来实现
//函数模板
template<class T>
bool myCompare(T &a, T&b)
{
if(a ==b)
{
return true;
}
return false;
}
//第三代具体化,如果能直接匹配,就优先调用
template bool myCompare<Person>(Person &a, Person &b)
{
if(a.age == b.age)
{
return true;
}
return false;
}
template <class NameType, class AgeName = int> //可以有默认类型参数
class Person
{
public:
Person(NameType name, AgeType age)
{
m_name = name;
m_age = age;
}
NameType m_name;
AgeType age;
};
Person<string, int> p("heihei",100); //函数模板可以进行自动类型推导,而类模板不行
类模板的成员函数在未确定时不会创建,只有确认了才会创建
template<class NameType, class AgeType>
class Person
{
public:
Person(NameType name, AgeType age)
{
this->m_name = name;
this->m_age = age;
}
NameType m_name;
AgeType m_age;
};
void doWork(Person<string,int> &p)
{
cout << "Name: " << p.m_name << endl;
cout << "Age: " << p.m_age << endl;
}
template<class T1, class T2>
void doWork2(Person<T1,T2> &p)
{
cout << "Name: " << p.m_name << endl;
cout << "Age: " << p.m_age << endl;
}
template <class T>
void doWork3(T &p)
{
//查看数据类型
cout << typeid(T).name() << endl;
cout << "Name: " << p.m_name << endl;
cout << "Age: " << p.m_age << endl;
}
template <class T>
class Person
{
public:
T m_A;
};
//在普通类继承之前,派生类必须知道基类的大小
//在继承时显式声明
class child : public Person<int>
{
public:
int m_B;
};
//当派生类是模板类时,可以模板化
template <class T1, class T2>
class child1 : public Person<T1>
{
public:
T2 m_c;
};
template <class T>
class Person
{
public:
Person();
void showPerson();
T m_A;
};
//类外实现成员函数
template <class T>
Person<T>::Person()
{
cout << "Person::person" << endl;
}
template <class T>
void Person<T>::showPerson()
{
cout << "Person::showPerson" << endl;
}
尽量不要份文件编写,写到一个文件即可, .hpp就是类模板的文件
//需要让编译器提前看到友元函数的声明,如下
template <class T>class Person3;
template <class T>void printPerson(Person3<T> &p);
template <class T>
class Person
{
//友元函数在类外实现,不加<>会将类外的实现当做函数模板,而类内的声明是一个普通函数,优先调用普通函数,而普通函数又没有声明,所以会报错
//加了<>之后,利用空参数列表,告诉编译器这是一个模板函数的声明
friend void printPerson<>(Person<T> &p);
//友元函数在类内实现,加了friend,编译器会自动认为这是一个全局函数
friend void printPerson(Person<T> &p)
{
cout << p.m_A << endl;
}
public:
Person(T num);
T m_A;
};
template <class T>
Person<T>::Person(T num)
{
this->m_A = num;
}
template <class T>
void printPerson(Person<T> &p)
{
cout << p.m_A << endl;
}
void test03()
{
Person3<int> p(100);
printPerson(p);
}
类型转换是将一种数据类型转换成另一种数据类型,转换是非常有用的,但是也会带来一些其他的问题,例如越界问题。尽量少的去做类型转换
//基本数据类型转换
void test01()
{
char a = 'a';
double b = static_cast<double>(a);
cout << "b = " << b << endl;
}
//父类和子类指针的转换
class Base{};
class Child : public Base{};
class Other{};
void test02()
{
Base* base = NULL;
Child* child = NULL;
//父类转子类,不安全
Child* child2 = static_cast<Child*>(base);
//子类转父类,安全
Base* base2 = static_cast<Base*>(child);
//错误,不能进行无关类型的转换
//Other* other = static_cast(base);
}
//父类和子类引用的转换
void test03()
{
Base base;
Child child;
Base &base1 = base;
Child &child1 = child;
//子转父
Base &base3 = static_cast<Base&>(child1);
//父转子
Child &child3 = static_cast<Child&>(base1);
}
有条件转换,动态类型转换,运行时类型安全检查(转换失败返回NULL)
class Base{
public:
virtual void print()
{
cout << "Base" << endl;
}
};
class Child : public Base
{
public:
virtual void print()
{
cout << "Child" << endl;
}
};
void test01()
{
//不支持基本类型
//char a = 'a';
//double b = dynamic_cast(a);
//父子转换中的安全类型
Base *base = NULL;
Child *child = new Child;
//子转父,安全
Base *base2 = dynamic_cast<Base*>(child);
base2->print();
//父转子,不安全,无法转换,但是使用多态之后就可以啦
Child *child2 = dynamic_cast<Child*>(base);
//child2->print();
}
class Base{
public:
virtual void print()
{
cout << "Base" << endl;
}
};
class Child : public Base
{
public:
virtual void print()
{
cout << "Child" << endl;
}
};
void test01()
{
//不支持基本类型
//char a = 'a';
//double b = dynamic_cast(a);
//父子转换中的安全类型
Base *base = NULL;
Child *child = new Child;
//子转父,安全
Base *base2 = dynamic_cast<Base*>(child);
base2->print();
//父转子,不安全,无法转换,但是使用多态之后就可以啦
Child *child2 = dynamic_cast<Child*>(base);
//child2->print();
}
最不安全的转换机制,仅仅重新解释类型,但没有进行二进制的转换: