第八层:模板(下)

简介: 第八层:模板(下)

代码验证:


#include<iostream>
using namespace std;
class A1
{
public:
  void print1()
  {
  cout << "A1在被调用" << endl;
  }
};
class A2
{
public:
  void print2()
  {
  cout << "A2在被调用" << endl;
  }
};
template<class T>
class A
{
public:
  void print1()
  {
  T a;
  a.print1();
  }
  void print2()
  {
  T a.print2();
  }
};
void test1()
{
  A<A1> a;
  a.print1();
  a.print2();
}
int main()
{
  test1();
  return 0;
}

0a2653c851af460fa595bd959398a8f1.png

代码在没有运行的时候,没有报错,在运行之后,会发现内部编译错误,是因为通用类型被定义为A1,A1中没有print2函数,现在注释掉,在来看看:


#include<iostream>
using namespace std;
class A1
{
public:
  void print1()
  {
  cout << "A1在被调用" << endl;
  }
};
class A2
{
public:
  void print2()
  {
  cout << "A2在被调用" << endl;
  }
};
template<class T>
class A
{
public:
  void print1()
  {
  T a;
  a.print1();
  }
  //void print2()
  //{
  //  T a.print2();
  //}
};
void test1()
{
  A<A1> a;
  a.print1();
  //a.print2();
}
int main()
{
  test1();
  return 0;
}

0eacb84100b54626af849e6b562bf92a.png

可以调用,这就是因为在确定通用类型之前没有生成内部函数,在确定好之后,会创建成员函数。


类模板对象做函数参数


类模板实例化出来的对象,可以做函数的参数吗?可以而且方法还不少:

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

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

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


指定传入类型


指定传入类型怎么去做?下面用代码来演示:


#include<string>
#include<iostream>
using namespace std;
template<class T1,class T2>
class per
{
public:
  per(T1 a, T2 b)
  {
  _name = a;
  _age = b;
  }
  T1 _name;
  T2 _age;
};
void print(per<string, int> p)
{
  cout << p._name << "的年龄" << p._age << "岁" << endl;
}
void test1()
{
  per<string, int> p("张三",18);
  print(p);
}
int main()
{
  test1();
  return 0;
}

0a2653c851af460fa595bd959398a8f1.png

直接将对象名前面的类名和模板的数据类型传过去就可以。


参数模板化


参数模板化,顾名思义,就是将参数变成和模板一样,模板有什么特点?通用的数据类型,就其实就是将模板的参数列表变成通用的数据类型即可:


#include<string>
#include<iostream>
using namespace std;
template<class T1,class T2>
class per
{
public:
  per(T1 a, T2 b)
  {
  _name = a;
  _age = b;
  }
  T1 _name;
  T2 _age;
};
template<class T1,class T2>
void print(per<T1,T2> p)
{
  cout << p._name << "的年龄" << p._age << "岁" << endl;
}
void test1()
{
  per<string, int> p("张三",18);
  print(p);
}
int main()
{
  test1();
  return 0;
}

0eacb84100b54626af849e6b562bf92a.png


将对象模型进行模板化


将对象模型进行模板化,就是将对象变成一个通用类型:


#include<string>
#include<iostream>
using namespace std;
template<class T1,class T2>
class per
{
public:
  per(T1 a, T2 b)
  {
  _name = a;
  _age = b;
  }
  T1 _name;
  T2 _age;
};
template<class T>
void print(T p)
{
  cout << p._name << "的年龄" << p._age << "岁" << endl;
}
void test1()
{
  per<string, int> p("张三",18);
  print(p);
}
int main()
{
  test1();
  return 0;
}

2d65d23f6d4748949b924e4057485923.png


类模板和继承


既然都是类,那类模板可以作为父类吗?被继承吗?是可以的,但是有需要注意的地方:


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

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

3.如果想灵活的指出父类中通用类型的类型,子类也需要变成类模板


第一点和第二点


因为在子类中会继承父类中的所有非静态成员变量,这个时候如果不知道父类中成员是什么类型,则编译器不知道应该分配多少内存给子类当中,所以要指定出来,那怎么指定呢?写法:

class 子类 : 继承方式 父类< 指定出类型 >

代码验证:


#include<iostream>
using namespace std;
template<class T1,class T2>
class per
{
public:
  per(T1 a, T2 b)
  {
  _name = a;
  _age = b;
  }
  T1 _name;
  T2 _age;
};
class per1 :public per
{
public:
};
int main()
{
  return 0;
}

2d65d23f6d4748949b924e4057485923.png

这个时候没有写,报错。


#include<string>
#include<iostream>
using namespace std;
template<class T1,class T2>
class per
{
public:
  per(T1 a, T2 b)
  {
  _name = a;
  _age = b;
  }
  T1 _name;
  T2 _age;
};
class per1 :public per<string ,int>
{
public:
};
int main()
{
  return 0;
}

2e9b90b2ca334476abebe75bafe6eeaa.png

写上之后不报错。


灵活指出父类中的类型


那怎么样才能灵活的指出呢?这个时候将子类变成模板即可:


#include<string>
#include<iostream>
using namespace std;
template<class T1,class T2>
class per
{
public:
  per(T1 a, T2 b)
  {
  _name = a;
  _age = b;
  }
  T1 _name;
  T2 _age;
};
template<class T,class T1>
class per1 :public per<T,T1>
{
public:
};
int main()
{
  return 0;
}

0a2653c851af460fa595bd959398a8f1.png

这个时候,这个T和T1就指向的是父类中的两个通用模板:

0eacb84100b54626af849e6b562bf92a.png


类模板成员函数类外实现


普通类的成员函数可以在类外实现,那类模板的是否可以?是可以的,有一定的语法格式,不仅仅要加作用域:

template < class T >

返回类型 类名< 参数 >:: 函数名 (T ____)

构造函数也可以进行类外实现,用代码验证一下:


#include<string>
#include<iostream>
using namespace std;
template<class T1,class T2>
class per
{
public:
  per(T1 a, T2 b);
  T1 _name;
  T2 _age;
};
template<class T1,class T2>
per<T1, T2>::per(T1 a, T2 b)
{
  _name = a;
  _age = b;
  cout << _name << "的年龄为" << _age << endl;
}
void test1()
{
  per<string, int>p("张三", 18);
}
int main()
{
  test1();
  return 0;
}

0a2653c851af460fa595bd959398a8f1.png


类模板的分文件编写


当代码量过大时,程序员通常会选择分文件编写,将声明实现和调用分开,那模板分开可以正常使用吗?

验证:


test.cpp

#include"per.h"
void test1()
{
  per<string, int>p("张三", 18);
}
int main()
{
  test1();
  return 0;
}

per.cpp

#include"per.h"
template<class T1, class T2>
class per
{
public:
  per(T1 a, T2 b)
  {
  _name = a;
  _age = b;
  cout << _name << "的年龄为" << _age << endl;
  }
  T1 _name;
  T2 _age;
};


per.h

#pragma once
#include<string>
#include<iostream>
using namespace std;
template<class T1, class T2>
class per;

0eacb84100b54626af849e6b562bf92a.png

是报错的,那这是为什么?上面说到,对于类模板中的成员函数在编译器阶段才去创建的,我们包含的头文件,那这个时候编译器就不会看到实现部分,只看到了声明,那这个时候可以将引的头文件该成实现的模块:


#include"per.cpp"
void test1()
{
  per<string, int>p("张三", 18);
}
int main()
{
  test1();
  return 0;
}

0a2653c851af460fa595bd959398a8f1.png

是可以正常使用的,那这个时候还可以将声明和实现放在一起,任何将后缀改为hpp,其他也可以,只是hpp是约定俗成的,一看上去就知道是模板的实现和定义。


类模板和友元


那类模板可以有友元函数吗?是可以拥有的,分为类内实现和类外实现


类内实现


类内实现直接在类捏将函数功能实现出来即可:


template<class T1,class T2>
class per
{
  friend void print(per<T1, T2> &p)
  {
  cout << _name << "的年龄为" << _age << endl;
  }
public:
  per(T1 a, T2 b)
  {
  _name = a;
  _age = b;
  }
private:
  string _name;
  int _age;
};


类外实现


template<class T1,class T2>
class per
{
  friend void print< >(per<T1, T2>& p);
public:
  per(T1 a, T2 b)
  {
  _name = a;
  _age = b;
  }
private:
  string _name;
  int _age;
};


类外实现时要注意,需要提前让编译器知道它存在,所以声明在类模板中。


注意


掌握模板不是为了写模板,而是为了使用第九层中的stl。


第九层…顶层?


看完上面的内容,我便踏入了前往第九层的楼梯,上来之后,抬头便是许久未见的天空…


相关文章
|
1月前
|
Python
模板
模板
63 4
|
1月前
树链剖分模板
树链剖分模板
33 0
|
1月前
|
Ubuntu Java Docker
Dockfile应用模板
Dockfile应用模板
75 0
|
1月前
|
C++
C++模板 - 模板的使用
C++模板 - 模板的使用
23 0
|
1月前
|
Java 编译器 程序员
C嘎嘎模板
C嘎嘎模板
33 0
|
9月前
|
算法
The Suspects (并查集问题模板)
The Suspects (并查集问题模板)
35 0
|
编译器 C++
C++之模板(上)
C++之模板(上)
64 0
|
编译器 C++