类模板

1.7 类模板

1.7.1 类模板基本概念

类模板和函数模板的定义和使用类似,我们已经进行了介绍。有时,有两个或多个类,其功能是相同的,仅仅是数据类型不同。

l  类模板用于实现类所需数据的类型参数化

template<class NameType, class AgeType>
class Person
{
public:
    Person(NameType name, AgeType age)
    {
        this->mName = name;
        this->mAge = age;
    }
    void showPerson()
    {
        cout << "name: " << this->mName << " age: " << this->mAge << endl;
    }
public:
    NameType mName;
    AgeType mAge;
};

void test01()
{
    //Person P1("德玛西亚",18); // 类模板不能进行类型自动推导 
    Person<string, int>P1("德玛西亚", 18);
    P1.showPerson();
}

1.7.2 类模板做函数参数

#include "stdafx.h"
#include <iostream>
using namespace std;
#include <string>

template <class NameType,class AgeType>
class Person
{
public:
    Person(NameType name, AgeType age)
    {
        this->m_Name = name;
        this->m_Age = age;
    }
    void PrintPerson()
    {
        cout << "Name:" << this->m_Name << " Age:" << this->m_Age << endl;
    }

    NameType m_Name;
    AgeType m_Age;
};

void DoBussiness(Person<string, int>& p)
{
    p.m_Age += 20;
    p.m_Name += "_VIP";
    p.PrintPerson();
}

//2.参数模板化
template<class T1,class T2>
void doWork(Person<T1, T2>&p)
{
    cout << typeid(T1).name() << endl;
    cout << typeid(T2).name() << endl;
    p.PrintPerson();
}

//3.整体类型化
template<class T>
void doWork3(T& p)
{
    cout << typeid(T).name() << endl;
    p.PrintPerson();
}

int main()
{
    Person<string,int> p("sunwukong", 100);
    //p.PrintPerson();
    DoBussiness(p);
    doWork(p);
    doWork3(p);
    return 0;
}

1.7.3 类模板派生普通类

//类模板
template<class T>
class MyClass{
public:
    MyClass(T property){
        this->mProperty = property;
    }
public:
    T mProperty;
};

//子类实例化的时候需要具体化的父类,子类需要知道父类的具体类型是什么样的
//这样c++编译器才能知道给子类分配多少内存

//普通派生类
class SubClass : public MyClass<int>{
public:
    SubClass(int b) : MyClass<int>(20){
        this->mB = b;
    }
public:
    int mB;
};
#include <iostream>
using namespace std;
#include <string>

template<class T>
class Base
{
public:
    T m_A;
};

class Child :public Base<int>
{
    
};

template <class T1,class T2>
class Child2 :public Base<T1>
{
public:
    T1 m_B;
};

int main()
{
    Child2<int, double> c2;
    return 0;
}

 

1.7.5 类模板类内实现

template<class NameType, class AgeType>
class Person
{
public:
    Person(NameType name, AgeType age)
    {
        this->mName = name;
        this->mAge = age;
    }
    void showPerson()
    {
        cout << "name: " << this->mName << " age: " << this->mAge << endl;
    }
public:
    NameType mName;
    AgeType mAge;
};

void test01()
{
    //Person P1("德玛西亚",18); // 类模板不能进行类型自动推导 
    Person<string, int>P1("德玛西亚", 18);
    P1.showPerson();
}

 

1.7.6 类模板类外实现

class Person{
public:
    Person(T1 name, T2 age);
    void showPerson();

public:
    T1 mName;
    T2 mAge;
};


//类外实现
template<class T1, class T2>
Person<T1, T2>::Person(T1 name, T2 age){
    this->mName = name;
    this->mAge = age;
}


template<class T1, class T2>
void Person<T1, T2>::showPerson(){
    cout << "Name:" << this->mName << " Age:" << this->mAge << endl;
}

void test()
{
    Person<string, int> p("Obama", 20);
    p.showPerson();
}

int main(){

    test();

    system("pause");
    return EXIT_SUCCESS;
}

 

1.7.7 类模板头文件和源文件分离问题

Person.hpp

#pragma once
#include <iostream>
using namespace std;

template<class T1,class T2>
class Person
{
public:
    Person(T1 t1, T2 t2);
    ~Person();
    void PrintInfo()
    {
        cout << "------------void PrintInfo()--------------" << endl;
        cout << "m_a: " << m_a  << " "<< typeid(T1).name() << endl;
        cout << "m_b: " << m_b  << " " <<typeid(T2).name() << endl;
        cout << "------------------------------------------" << endl;
    }
    void showInfo();
    T1 m_a;
    T2 m_b;
};

template<class T1,class T2,class T3>
class xiaoming :public Person<T1, T2>
{
public:
    xiaoming(T1 a, T2 b, T3 c);
    ~xiaoming();
    void showInfo();
    T3 m_c;
};

template<class T1, class T2>
Person<T1, T2>::Person(T1 t1, T2 t2)
    :m_a(t1)
    , m_b(t2)
{
}


template<class T1, class T2>
Person<T1, T2>::~Person()
{
}

template<class T1, class T2>
void Person<T1, T2>::showInfo()
{
    cout << "---------------void Person<T1,T2>::showInfo()---------------" << endl;
    cout << "m_a: " << m_a << " " << "m_b: " << m_b << " " << endl;
    cout << "--------------------------------------------------------------" << endl;
}

template<class T1, class T2, class T3>
xiaoming<T1, T2, T3>::xiaoming(T1 a, T2 b, T3 c)
    :Person(a, b)
    , m_c(c)
{
}

template<class T1, class T2, class T3>
xiaoming<T1, T2, T3>::~xiaoming()
{

}

template<class T1, class T2, class T3>
void xiaoming<T1, T2, T3>::showInfo()
{
    cout << "---------void xiaoming<T1, T2, T3>::showInfo()----------" << endl;
    cout << "m_a: " << m_a << " " << typeid(T1).name() << endl;
    cout << "m_b: " << m_b << " " << typeid(T2).name() << endl;
    cout << "m_c: " << m_c << " " << typeid(T3).name() << endl;
    cout << "--------------------------------------------------------" << endl;
}

 

调用

#include "stdafx.h"
#include <iostream>
using namespace std;
#include <string>
//#include "Person.h"
#include "Person.hpp"

int main()
{
    //Child2<int, double> c2;
    Person<int, string> p1(10,"test p1");
    p1.showInfo();
    p1.PrintInfo();

    xiaoming<int, string, int> p2(10, "xiaoming", 1000);
    p2.showInfo();
    p2.PrintInfo();
    return 0;
}

 

结论: 案例代码在qt编译器顺利通过编译并执行,但是在Linux和vs编辑器下如果只包含头文件,那么会报错链接错误,需要包含cpp文件,但是如果类模板中有友元类,那么编译失败!

解决方案: 类模板的声明和实现放到一个文件中,我们把这个文件命名为.hpp(这个是个约定的规则,并不是标准,必须这么写).

原因:

类模板需要二次编译,在出现模板的地方编译一次,在调用模板的地方再次编译。

C++编译规则为独立编译。

1.7.8     模板类碰到友元函数

// Template02.cpp : 定义控制台应用程序的入口点。
//

#include "stdafx.h"

#include <iostream>
using namespace std;
#include <string>

//2.2 外部实现1 前置声明
template<class T1, class T2> class Person;
//2.3 外部实现1 外部声明友元
template<class T1, class T2> void PrintPerson2(Person<T1, T2>& p);

template<class T1,class T2>
class Person
{
    //3 外部实现2
    template<class U1, class U2>
    friend void PrintPerson3(Person<U1, U2>& p);

    //2.1外部实现1
    friend void PrintPerson2<>(Person<T1, T2>& p);

    //1.内部实现
    friend void PrintPerson(Person<T1, T2>& p) {
        cout << "Name:" << p.m_Name << " Age:" << p.m_Age << endl;;
    }

    

public:
    Person(T1 name, T2 age)
    {
        this->m_Name = name;
        this->m_Age = age;
    }

    void showPerson()
    {
        cout << "Name:" << this->m_Name << " Age:" << this->m_Age << endl;
    }
private:
    T1 m_Name;
    T2 m_Age;
};

template<class T1,class T2>
void PrintPerson2(Person<T1, T2>& p)
{
    cout << "Name:" << p.m_Name << " Age:" << p.m_Age << endl;
}


template<class U1, class U2>
void PrintPerson3(Person<U1, U2>& p)
{
    cout << "Name:" << p.m_Name << " Age:" << p.m_Age << endl;
}
int main()
{
    Person<string, int> p("sunwukong", 20);
    //p1.showPerson();
    //PrintPerson2(p);
    PrintPerson3(p);
    return 0;
}

 

posted @ 2019-02-28 21:35  吹过田野的风  阅读(185)  评论(0编辑  收藏  举报