2020-02-19 C++提高编程02-基本框架

1.3类模板

1.3.1类模板语法

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

语法: 

template<class T>

解释:

template :声明创建模板

class/typename :表明其后面的符号是一种数据类型

T  :通用数据类型,通常为大写字母

示例:

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;

};

1.3.2类模板与函数模板区别

1.类模板没有自动类型推导的使用方式;

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

示例:

template<class NameType, class AgeType=int>

class Person

{

public:

Person(NameType name, AgeType age)

{

this->m_Name = name;

this->m_Age = age;

}

NameType m_Name;

AgeType m_Age;

};

void test01()

{

//无法使用自动类型推导

//Person p("Mike", 20);//error

Person<string,int>p("Mike", 20);

}

void test02()

{

Person<string>p("Mike", 20);//ok 因为模板参数列表设置了默认参数

}


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

类模板中成员函数和普通类中成员函数创建时机是有区别的:

1.普通类中成员函数一开始就可以创建;

2.类模板中成员函数在调用时才创建;

示例:

class Person1

{

public:

void showPerson1()

{

cout << "showPerson1()" << endl;

}

};

class Person2

{

public:

void showPerson2()

{

cout << "showPerson2()" << endl;

}

};

template <class T>

class MyClass

{

public:

T obj;

//类模板中的成员函数,并不是一开始就创建的,而是在模板调用时再生成

void func1()

{

obj.showPerson1();

}

void func2()

{

obj.showPerson2();

}

};

void test01()

{

MyClass<Person1> m;

m.func1();

//m.func2();//error

//编译会出错,说明函数调用才会去创建成员函数

}

1.3.4类模板对象做函数参数

要点:类模板实例化出的对象,向函数传参的方式

一共有三种传入方式:

1.指定传入的类型  ---直接显示对象的数据类型

2.参数模板化    ---将对象中的参数变为模板进行传递

3.整个类模板化    ---将这个对象类型 模板化进行传递、

示例:

template <class T1, class T2>

class Person

{

public:

Person(T1 name, T2 age)

{

this->m_Name = name;

this->m_Age = age;

}

void showPerson()

{

cout << "name: " << this->m_Name << endl

<< "age: " << this->m_Age << endl;

}

T1 m_Name;

T2 m_Age;

};

//1.指定传入类型

void printPerson1(Person<string, int> &p)

{

p.showPerson();

}

void test01()

{

Person<string, int> p("Mike", 20);

printPerson1(p);

}

//2.参数模板化

template <class T1, class T2>

void printPerson2(Person<T1, T2> &p)

{

p.showPerson();

cout << "type of T1: " << typeid(T1).name() <<endl

<< "type of T2: " << typeid(T2).name() << endl;

}

void test02()

{

Person<string, int> p("Jack", 22);

printPerson2(p);

}

//3.这个类模板化

template <class T>

void printPerson3(T &p)

{

p.showPerson();

cout << "type of T: " << typeid(T).name() << endl;

}

void test03()

{

Person<string, int> p("Mary", 18);

printPerson3(p);

}

总结:

1.通过类模板创建的对象,可以有三种方式向函数中进行传参;

2.第一种指定传入类型 使用的比较广泛;

1.3.5类模板与继承

1.当子类继承的父类是一个类模板时,子类在声明时,要指定出父类中T的类型;

2.如果不指定,编译器无法给子类分配内存;

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

示例:

template <class T>

class Base

{

public:

T m;

};

class Son//:public Base//error 必须要知道父类中T类型,才能继承给子类

:public Base<int>{};

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

template <class T1,class T2>

class Son2:public Base<T2>

{

public:

T1 obj;

};

void test02()

{

Son2<int,char> s2;

}

总结:如果父类是类模板,子类需要指定出父类中T的数据类型

1.3.6类模板成员函数类外实现

示例:

template<class T1,class T2>

class Person

{

public:

Person(T1 name, T2 age);

void showPerson();

T1 m_Name;

T2 m_Age;

};

template<class T1, class T2>

Person<T1,T2>::Person(T1 name, T2 age)

{

this->m_Name = name;

this->m_Age = age;

}

template<class T1, class T2>

void Person<T1, T2>::showPerson()

{

cout << "name: " << this->m_Name << endl

<< "age: " << this->m_Age << endl;

}

总结:

1.函数实现体前需要声明是模板;

2.在类名之后加模板参数列表;

1.3.7类模板分文件编写

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

解决:

1.直接包含.cpp源文件;

2.将声明和实现写到同一个文件中,并更改后缀名为 .hpp (约定名称,而非强制)

注:主要采用第二种,将类模板成员函数写到一起,并更改后缀为.hpp

示例:

1.person.hpp文件

#pragma once

#include <iostream>

#include <string>

using namespace std;

template<class T1, class T2>

class Person

{

public:

Person(T1 name, T2 age);

void showPerson();

T1 m_Name;

T2 m_Age;

};

template<class T1, class T2>

Person<T1, T2>::Person(T1 name, T2 age)

{

this->m_Name = name;

this->m_Age = age;

}

template<class T1, class T2>

void Person<T1, T2>::showPerson()

{

cout << "name: " << this->m_Name << endl

<< "age: " << this->m_Age << endl;

}

2.实现文件

#include "person.hpp"

...

1.3.8类模板与友元

要点:掌握类模板配合友元函数的类内和类外实现

全局函数类内实现-直接在类内声明友元即可;

全局函数类外实现-需要提前让编译器知道全局函数的存在;

示例:

1.类内实现

template<class T1, class T2>

class Person

{

friend void printPerson(Person<T1, T2> p)

{

cout << "name: " << p.m_Name << endl

<< "age: " << p.m_Age << endl;

}

public:

Person(T1 name, T2 age)

{

this->m_Name = name;

this->m_Age = age;

}

private:

T1 m_Name;

T2 m_Age;

};

2.类外实现

//提前让编译器知道Person类存在

template<class T1, class T2>

class Person;

//提前让编译器知道这个全局函数的存在

//函数模板声明

template<class T1, class T2>

void printPerson2(Person<T1, T2> p)

{

cout << "name: " << p.m_Name << endl

<< "age: " << p.m_Age << endl;

}

template<class T1, class T2>

class Person

{   

    //error 普通函数声明 并非函数模板声明

//friend void printPerson2(Person<T1, T2> p);

//如果全局函数是类外实现,需要让编译器提前知道这个函数的存在

friend void printPerson2<>(Person<T1, T2> p);

public:

Person(T1 name, T2 age)

{

this->m_Name = name;

this->m_Age = age;

}

private:

T1 m_Name;

T2 m_Age;

};

总结:建议全局函数做类内实现,用法简单,而且编译器可以直接识别;

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。