Skip to content

Latest commit

 

History

History
145 lines (126 loc) · 2.94 KB

l_17.md

File metadata and controls

145 lines (126 loc) · 2.94 KB

Lesson17 类模板深入



1. 类模板和函数

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

struct A {
  void showA();
};

struct B {
  void showB();
};

template <typename T>
struct Show {
  void func1() {
    obj.showA();
  }
  void func2() {
    obj.showB();
  }

  T obj;
};

为了保证上述代码中类模板能够在如下代码中成功执行,成员函数在被调用前不会被创建。普通成员函数在调用前已经被创建。

Show<A> s;
s.func1();
s.func2();    // error

类模板对象作函数参数

template <typename T1, typename T2>
class AA {
 public:
  AA(T1 n, T2 m)
    : _n(n), _m(m) {}

  T1 _n;
  T2 _m;
};

一共有三种传参方式

  • 指定传入类型
    void func(AA<int, double>& obj);
  • 参数模板化
    template <typename T1, typename T2>
    void func(AA<T1, T2>& obj);
  • 整个类模板化
    template <typename T>
    void func(T& obj);
    拓展一点,我们还可以写个模板模板参数(C++17)
    template <typename T1, typename T2, template <typename T1, typename T2> class C>
    void func(C<T1, T2>& obj);

当我们调用函数时,以上三(+1)种调用方式都可以实现传参

AA<int, double>a(10, 9.9);
func(a);

实际开发中,我们更常用第一(四)种传参方式


2. 类模板和继承

当子类继承的基类是一个模板类时,子类在声明的时候要指定出基类中T的类型。如果不指定,编译器无法给子类分配内存。

template<typename T>
class Base {
  T m;
};

class Derived : public Base<int> {};

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

template<typename T1, typename T2>
class Derived : public Base<T2> {
  T1 obj;
};

3. 类模板和友元

通过全局函数做友元(类内实现)访问类内成员

template<typename T1, typename T2>
class AA {
  friend void show(AA<T1, T2>a) {
    std::cout << a._n << a._m << std::endl;
  }

  T1 _n;
  T2 _m;

 public:
  AA(int n, int m)
    : _n(n), _m(m) {}
};

通过全局函数做友元(类外实现)访问类内成员

template<typename T1, typename T2>
class AA;   // 声明存在类AA

template<typename T1, typename T2>
void show(AA<T1, T2>a) {      // 函数提前声明并定义
  std::cout << a._n << a._m << std::endl;
}

template<typename T1, typename T2>
class AA {
  // 加空模板参数列表强制调用模板函数
  friend void show<>(AA<T1, T2>a);

  T1 _n;
  T2 _m;

 public:
  AA(int n, int m)
    : _n(n), _m(m) {}
};

edit Serein