C++类模板:1.类模板语法 2.类模板和函数模板的区别 3.类模板中成员函数创建时机 4.类模板对象做函数参数的三种方法 5.两种方法继承类模板 6.模板类构造函数,普通函数的类外实现

一.类模板定义

1.1 是什么

建立一个通用的类,类中的成员 数据类型可以不具体制定,用一个虚拟的类型来代表。

1.2 定义语法

template<typename T>
template: 是声明创建模板
tupename: 后跟数据类型,可以用class代替
T : 通用的数据类型,名称可以替换。

1.3 示例

#include
#include
using namespace std;

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 showPerson()
        {
            cout<<"name: "<<this->m_Name << " age: "<<this->m_Age<<endl;
        }
};

void test01()
{
    Person<string,int> p1("孙悟空",999);
    p1.showPerson();
    
}

int main()
{
    test01();
    return 0;
}

二.类模板和函数模板的区别

1.类模板没有自动类型推导的使用方式,必须指明类型。
	如: Person p("孙悟空",100); 错误
			Person<string,int>p("孙悟空",100); 正确

2.类模板在模板参数列表中可以有默认参数。

三.类模板中成员函数创建时机

1.普通类中的成员函数一开始就创建了
2.类模板中的成员函数在调用时才创建

四.类模板对象做函数参数的三种方法

#include
#include
using namespace std;


template<class T1,class T2>
class Person
{
public:
    Person(T1 name,T2 age)
    {
        this->m_Name = name;
        this->m_Age = age;
    }
    T1 m_Name;
    T2 m_Age;
    void showPerson()
    {
        cout<<"姓名: "<<this->m_Name<<" 年龄: "<<this->m_Age<<endl;
    }
};

// 1.类模板对象做函数参数的传递方法一:指定传入类型

void printPerson1(Person<string,int>&p)
{
    p.showPerson();
}

void test01()
{
    Person<string,int>p("孙悟空",100);
    printPerson1(p);
}

// 2.类模板对象做函数参数的传递方法二:把参数模板化
template<class T1,class T2>
void printPerson2(Person<T1,T2>&p)
{
    p.showPerson();
    cout<<"T1 的类型为: "<<typeid(T1).name()<<endl;
    cout<<"T2 的类型为: "<<typeid(T2).name()<<endl;             
}
void test02()
{
    Person<string,int>p("猪八戒",90);
    printPerson2(p);
}

// 3.类模板对象做函数参数的传递方法三:整个类模板化
template<class T>
void printPerson3(T &p)
{
    p.showPerson();
    cout<<"T的数据类型为: "<<typeid(T).name()<<endl;
}
void test03()
{
    Person<string,int>p("唐僧",30);
    printPerson3(p);
}

int main()
{
    // 1.类模板对象做函数参数的传递方法一:指定传入类型
    // test01();

    // 2.类模板对象做函数参数的传递方法一:把参数模板化
    // test02();

    // 3.类模板对象做函数参数的传递方法三:整个类模板化
    test03();
    return 0;
}

五.继承类模板

5.1 通过指定父类数据类型继承类模板

#include
using namespace std;

// 类模板与继承
template<class T>
class Base
{
    T m;
};

// 如果不指定父类的数据类型,那么子类无法分配内存空间,就无法继承。
class Son: public Base<int>
{

};

void test01()
{
    Son s1;
}
缺点:子类指定了数据类型,这个数据类型就不能变了。

5.2 灵活指定父类中的T类型

如果想灵活指定父类中的T类型,子类也需要变类模板

//.如果想灵活指定父类中的T类型,子类也需要变类模板
template<class T1,class T2>
class Son2:public Base<T2>
{
public:
    Son2()
    {
        cout<<"T1的类型为:"<<typeid(T1).name()<<endl;
    }
    T1 obj;
};

void test02()
{
    Son2<int,char>S2;
}

测试代码:

int main()
{
    test02();
    return 0;
}

六.模板类构造函数,普通函数的类外实现

1.类外实现模板类的构造函数

模板定义
模板类作用域作用域:: 构造函数名

2.类外实现模板类的普通函数

模板定义
函数返回值 模板类作用域:: 普通函数名

案例:

#include
using namespace std;

template<class T1,class T2>
class Person
{
public:
    Person(T1 name,T2 age);

    void showPerson();

    T1 m_Name;
    T2 m_Age;
};

// 1.构造函数类外实现
template<class T1,class T2>
Person<T1,T2>::Person(T1 name,T2 age)
{
    this->m_Name = name;
    this->m_Age = age;
}

// 2.成员函数类外实现
template<class T1,class T2>
void Person<T1,T2>::showPerson()
{
    cout<<"姓名: "<<this->m_Name<<"年龄: "<<this->m_Age<<endl;
}

void test01()
{
    Person<string,int> P("Tom",20);
    P.showPerson();
}


int main()
{
    test01();
    return 0;
}

七.类模板分文件编写

类模板成员函数的创建时机是在调用阶段,导致分文件编写时链接不到。

如:导入.h包,结果编译报错:
C++类模板:1.类模板语法 2.类模板和函数模板的区别 3.类模板中成员函数创建时机 4.类模板对象做函数参数的三种方法 5.两种方法继承类模板 6.模板类构造函数,普通函数的类外实现_第1张图片

因为类模板成员函数一开始是不会创建的,当你去包含.h的时候,相当于只是让编译器看到了如下声明的代码。编译器没有看到实现构造函数和 void showPerson()的代码。所以链接阶段失败。
C++类模板:1.类模板语法 2.类模板和函数模板的区别 3.类模板中成员函数创建时机 4.类模板对象做函数参数的三种方法 5.两种方法继承类模板 6.模板类构造函数,普通函数的类外实现_第2张图片

解决方法

1:直接包含.cpp源文件 
2.将声明和实现写到同一个文件中,并更改后缀名为.hpp,.hpp是约定的名称。

7.1 直接包含.cpp源文件

把 .h改为.cpp时,相当于让编译器看到了如下实现的代码:
C++类模板:1.类模板语法 2.类模板和函数模板的区别 3.类模板中成员函数创建时机 4.类模板对象做函数参数的三种方法 5.两种方法继承类模板 6.模板类构造函数,普通函数的类外实现_第3张图片
此时编译器可以成功编译了。
但是一般不用这种方法,因为一般是不会直接导入cpp源码的。

7.2 将.h和.cpp中的声明和实现内容写到一起,将后缀名改为.hpp文件

你可能感兴趣的:(C++笔记,c++,算法,开发语言)