第八层:模板(下)

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

代码验证:


#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。


第九层…顶层?


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


相关文章
|
3天前
|
数据采集 人工智能 安全
|
13天前
|
云安全 监控 安全
|
4天前
|
自然语言处理 API
万相 Wan2.6 全新升级发布!人人都能当导演的时代来了
通义万相2.6全新升级,支持文生图、图生视频、文生视频,打造电影级创作体验。智能分镜、角色扮演、音画同步,让创意一键成片,大众也能轻松制作高质量短视频。
1085 152
|
18天前
|
机器学习/深度学习 人工智能 自然语言处理
Z-Image:冲击体验上限的下一代图像生成模型
通义实验室推出全新文生图模型Z-Image,以6B参数实现“快、稳、轻、准”突破。Turbo版本仅需8步亚秒级生成,支持16GB显存设备,中英双语理解与文字渲染尤为出色,真实感和美学表现媲美国际顶尖模型,被誉为“最值得关注的开源生图模型之一”。
1751 9
|
9天前
|
人工智能 自然语言处理 API
一句话生成拓扑图!AI+Draw.io 封神开源组合,工具让你的效率爆炸
一句话生成拓扑图!next-ai-draw-io 结合 AI 与 Draw.io,通过自然语言秒出架构图,支持私有部署、免费大模型接口,彻底解放生产力,绘图效率直接爆炸。
694 152
|
11天前
|
人工智能 安全 前端开发
AgentScope Java v1.0 发布,让 Java 开发者轻松构建企业级 Agentic 应用
AgentScope 重磅发布 Java 版本,拥抱企业开发主流技术栈。
660 14
|
6天前
|
SQL 自然语言处理 调度
Agent Skills 的一次工程实践
**本文采用 Agent Skills 实现整体智能体**,开发框架采用 AgentScope,模型使用 **qwen3-max**。Agent Skills 是 Anthropic 新推出的一种有别于mcp server的一种开发方式,用于为 AI **引入可共享的专业技能**。经验封装到**可发现、可复用的能力单元**中,每个技能以文件夹形式存在,包含特定任务的指导性说明(SKILL.md 文件)、脚本代码和资源等 。大模型可以根据需要动态加载这些技能,从而扩展自身的功能。目前不少国内外的一些框架也开始支持此种的开发方式,详细介绍如下。
438 5