template
template
The concept of a template
A template establishes a general mold, greatly improving reusability.
For example, templates in daily life
One-inch photo template:

PowerPoint template:


Features of the template:
- The template cannot be used directly; it is only a framework.
- Templates are generally applicable, but not universal.
function template
- Another programming concept in C++ is called generic programming, which primarily leverages templates.
- C++ provides two template mechanisms: function templates and class templates.
Function template syntax
Function template purpose:
Create a generic function where the return type and parameter types do not need to be explicitly specified, using a virtual type to represent them.
Syntax:
template<typename T>
函数声明或定义
Run/Observation Results: This section is syntax definition-focused, typically requiring compilation together with the calling code. Pay attention to the definition method and usage location.
Explanation:
template --- Declare Template Creation
typename --- indicates that the subsequent symbol is a data type and can be replaced with class
T --- Generic data type; the name can be substituted, typically uppercase letters
Example:
//交换整型函数
void swapInt(int& a, int& b) {
int temp = a;
a = b;
b = temp;
}
//交换浮点型函数
void swapDouble(double& a, double& b) {
double temp = a;
a = b;
b = temp;
}
//利用模板提供通用的交换函数
template<typename T>
void mySwap(T& a, T& b)
{
T temp = a;
a = b;
b = temp;
}
void test01()
{
int a = 10;
int b = 20;
//swapInt(a, b);
//利用模板实现交换
//1、自动类型推导
mySwap(a, b);
//2、显示指定类型
mySwap<int>(a, b);
cout << "a = " << a << endl;
cout << "b = " << b << endl;
}
int main() {
test01();
return 0;
}
Running/Observation Results: After running, the corresponding content will be printed according to the output statements. The variable values can be inferred based on the order of initialization, assignment, and function calls.
Summary:
- Function templates utilize the keyword "template"
- There are two ways to use function templates: automatic type deduction and explicit type specification.
- The purpose of templates is to enhance reusability by parameterizing types.
Function template considerations: syntax, type deduction, specialization, and potential pitfalls.
Notes:
- Automatic type deduction must resolve to a consistent data type T before use.
- Templates must have the data type of T specified to be used.
Example:
//利用模板提供通用的交换函数
template<class T>
void mySwap(T& a, T& b)
{
T temp = a;
a = b;
b = temp;
}
// 1、自动类型推导,必须推导出一致的数据类型T,才可以使用
void test01()
{
int a = 10;
int b = 20;
char c = 'c';
mySwap(a, b); // 正确,可以推导出一致的T
//mySwap(a, c); // 错误,推导不出一致的T类型
}
// 2、模板必须要确定出T的数据类型,才可以使用
template<class T>
void func()
{
cout << "func 调用" << endl;
}
void test02()
{
//func(); //错误,模板不能独立使用,必须确定出T的类型
func<int>(); //利用显示指定类型的方式,给T一个类型,才可以使用该模板
}
int main() {
test01();
test02();
return 0;
}
Running/Observation Results: After running, the corresponding content will be printed according to the output statements. The variable values can be inferred based on the order of initialization, assignment, and function calls.
Summary:
- When using templates, you must determine the generic data type T and be able to deduce a consistent type.
Function Template Examples
Case description:
- Encapsulate a sorting function using function templates to sort arrays of different data types.
- Sorting rule from largest to smallest, sorting algorithm is selection sort.
- Testing separately using char arrays and int arrays.
Example:
//交换的函数模板
template<typename T>
void mySwap(T &a, T&b)
{
T temp = a;
a = b;
b = temp;
}
template<class T> // 也可以替换成typename
//利用选择排序,进行对数组从大到小的排序
void mySort(T arr[], int len)
{
for (int i = 0; i < len; i++)
{
int max = i; //最大数的下标
for (int j = i + 1; j < len; j++)
{
if (arr[max] < arr[j])
{
max = j;
}
}
if (max != i) //如果最大数的下标不是i,交换两者
{
mySwap(arr[max], arr[i]);
}
}
}
template<typename T>
void printArray(T arr[], int len) {
for (int i = 0; i < len; i++) {
cout << arr[i] << " ";
}
cout << endl;
}
void test01()
{
//测试char数组
char charArr[] = "bdcfeagh";
int num = sizeof(charArr) / sizeof(char);
mySort(charArr, num);
printArray(charArr, num);
}
void test02()
{
//测试int数组
int intArr[] = { 7, 5, 8, 1, 3, 9, 2, 4, 6 };
int num = sizeof(intArr) / sizeof(int);
mySort(intArr, num);
printArray(intArr, num);
}
int main() {
test01();
test02();
return 0;
}
Running/Observing the results: After running, the example will print variable values or addresses; address values depend on the runtime environment, so focus on observing the relative positioning and pointer changes of similar objects.
Summary: Templates can improve code reusability and require proficiency to master.
Difference Between Regular Functions and Function Templates
A regular function is defined for specific parameter types, requiring explicit type definitions during declaration. A function template, however, is a blueprint for generating functions, where parameter types are specified as placeholders—allowing the compiler to automatically deduce or instantiate the appropriate function version based on the actual arguments provided. While regular functions lead to potential code duplication when handling multiple data types, function templates eliminate redundancy by enabling a single definition to operate across various types. Templates are resolved at compile time, generating specialized code as needed, whereas regular functions are directly compiled and linked. Use templates when logic is consistent but data types may vary; opt for regular functions when operations are type-specific or require explicit control over implementation details.
Difference Between Regular Functions and Function Templates:
- Automatic type conversion (implicit type conversion) can occur during ordinary function calls.
- When invoking function templates, implicit type conversions do not occur if automatic type deduction is used.
- If using the specified type, implicit type conversion can occur.
Example:
//普通函数
int myAdd01(int a, int b)
{
return a + b;
}
//函数模板
template<class T>
T myAdd02(T a, T b)
{
return a + b;
}
//使用函数模板时,如果用自动类型推导,不会发生自动类型转换,即隐式类型转换
void test01()
{
int a = 10;
int b = 20;
char c = 'c';
cout << myAdd01(a, c) << endl; //正确,将char类型的'c'隐式转换为int类型 'c' 对应 ASCII码 99
//myAdd02(a, c); // 报错,使用自动类型推导时,不会发生隐式类型转换
myAdd02<int>(a, c); //正确,如果用显示指定类型,可以发生隐式类型转换
}
int main() {
test01();
return 0;
}
Running/Observation Results: After running, the corresponding content will be printed according to the output statements. The variable values can be inferred based on the order of initialization, assignment, and function calls.
Summary: It is recommended to explicitly specify types when calling a function template, as this allows you to determine the generic type T yourself.
Calling Rules for Regular Functions vs. Function Templates
The call rules are as follows:
- If both a function template and a regular function can be implemented, the regular function is called with priority.
- You can enforce a function template invocation using an empty template parameter list.
- Function templates can also be overloaded.
- If a function template can produce a better match, it is preferred over a non-template function.
Example:
//普通函数与函数模板调用规则
void myPrint(int a, int b)
{
cout << "调用的普通函数" << endl;
}
template<typename T>
void myPrint(T a, T b)
{
cout << "调用的模板" << endl;
}
template<typename T>
void myPrint(T a, T b, T c)
{
cout << "调用重载的模板" << endl;
}
void test01()
{
//1、如果函数模板和普通函数都可以实现,优先调用普通函数
// 注意 如果告诉编译器 普通函数是有的,但只是声明没有实现,或者不在当前文件内实现,就会报错找不到
int a = 10;
int b = 20;
myPrint(a, b); //调用普通函数
//2、可以通过空模板参数列表来强制调用函数模板
myPrint<>(a, b); //调用函数模板
//3、函数模板也可以发生重载
int c = 30;
myPrint(a, b, c); //调用重载的函数模板
//4、 如果函数模板可以产生更好的匹配,优先调用函数模板
char c1 = 'a';
char c2 = 'b';
myPrint(c1, c2); //调用函数模板
}
int main() {
test01();
return 0;
}
Running/Observation Results: After running, the corresponding content will be printed according to the output statements. The variable values can be inferred based on the order of initialization, assignment, and function calls.
In summary: Since function templates are provided, it's best not to provide regular functions to avoid potential ambiguity.
Limitations of templates
Limitations:
- The general applicability of the template isn't omnipotent.
For example:
template<class T>
void f(T a, T b)
{
a = b;
}
Run/Observation Results: This section is syntax definition-focused, typically requiring compilation together with the calling code. Pay attention to the definition method and usage location.
In the code provided above, the assignment operation as implemented cannot handle cases where the input parameters a and b are arrays.
Another example:
template<class T>
void f(T a, T b)
{
if(a > b) { ... }
}
Run/Observation Results: This is a syntax fragment, focus on the writing style; run it after completing the context.
In the provided code, if T is a custom data type like Person, it still will not run properly.
Therefore, in order to address such issues, C++ provides template overloading, which allows for concrete templates to be defined for these specific types.
Example:
#include<iostream>
using namespace std;
#include <string>
class Person
{
public:
Person(string name, int age)
{
this->m_Name = name;
this->m_Age = age;
}
string m_Name;
int m_Age;
};
//普通函数模板
template<class T>
bool myCompare(T& a, T& b)
{
if (a == b)
{
return true;
}
else
{
return false;
}
}
//具体化,显示具体化的原型和定意思以template<>开头,并通过名称来指出类型
//具体化优先于常规模板
template<> bool myCompare(Person &p1, Person &p2)
{
if ( p1.m_Name == p2.m_Name && p1.m_Age == p2.m_Age)
{
return true;
}
else
{
return false;
}
}
void test01()
{
int a = 10;
int b = 20;
//内置数据类型可以直接使用通用的函数模板
bool ret = myCompare(a, b);
if (ret)
{
cout << "a == b " << endl;
}
else
{
cout << "a != b " << endl;
}
}
void test02()
{
Person p1("Tom", 10);
Person p2("Tom", 10);
//自定义数据类型,不会调用普通的函数模板
//可以创建具体化的Person数据类型的模板,用于特殊处理这个类型
bool ret = myCompare(p1, p2);
if (ret)
{
cout << "p1 == p2 " << endl;
}
else
{
cout << "p1 != p2 " << endl;
}
}
int main() {
test01();
test02();
return 0;
}
Running/Observing the results: After running, the example will print variable values or addresses; address values depend on the runtime environment, so focus on observing the relative positioning and pointer changes of similar objects.
Summary:
- Using concrete templates can solve the generalization of custom types.
- Learning templates is not about writing templates, but about using the STL system-provided templates.
class template
Class template syntax
Class Template Purpose:
- Create a generic class where the member data types do not need to be specifically defined, using a generic type to represent them.
Syntax:
template<typename T>
类
Run/Observation Results: This section is syntax definition-focused, typically requiring compilation together with the calling code. Pay attention to the definition method and usage location.
Explanation:
template --- Declare Template Creation
typename --- indicates that the subsequent symbol is a data type and can be replaced with class
T --- Generic data type; the name can be substituted, typically uppercase letters
Example:
#include <string>
//类模板
template<class NameType, class AgeType>
class Person
{
public:
Person(NameType name, AgeType age)
{
this->mName = name;
this->mAge = age;
}
void showPerson()
{
cout << "name: " << this->mName << " age: " << this->mAge << endl;
}
public:
NameType mName;
AgeType mAge;
};
void test01()
{
// 指定NameType 为string类型,AgeType 为 int类型
Person<string, int>P1("孙悟空", 999);
P1.showPerson();
}
int main() {
test01();
return 0;
}
Running/Observing the results: After running, the example will print variable values or addresses; address values depend on the runtime environment, so focus on observing the relative positioning and pointer changes of similar objects.
Summary: Class templates and function templates have similar syntax, with a class declared after the template keyword being called a class template.
The Differences Between Class Templates and Function Templates
The two main differences between class templates and function templates are as follows:
- 类模板没有自动类型推导的使用方式,也就是说,在使用类模板时必须显式指定模板参数类型。函数模板支持自动类型推导,但类模板通常需要显式指定类型。不过,C++17引入了类模板参数推导(CTAD)特性,允许在某些情况下自动推导类模板的参数类型。
- Class templates can have default arguments in the template parameter list.
Example:
#include <string>
//类模板
template<class NameType, class AgeType = int>
class Person
{
public:
Person(NameType name, AgeType age)
{
this->mName = name;
this->mAge = age;
}
void showPerson()
{
cout << "name: " << this->mName << " age: " << this->mAge << endl;
}
public:
NameType mName;
AgeType mAge;
};
//1、类模板没有自动类型推导的使用方式
void test01()
{
// Person p("孙悟空", 1000); // 错误 类模板使用时候,不可以用自动类型推导
Person <string ,int>p("孙悟空", 1000); //必须使用显示指定类型的方式,使用类模板
p.showPerson();
}
//2、类模板在模板参数列表中可以有默认参数
void test02()
{
Person <string> p("猪八戒", 999); //类模板中的模板参数列表 可以指定默认参数
p.showPerson();
}
int main() {
test01();
test02();
return 0;
}
Running/Observing the results: After running, the example will print variable values or addresses; address values depend on the runtime environment, so focus on observing the relative positioning and pointer changes of similar objects.
Summary:
- Class templates can only be used with explicit type specification.
- The template parameter list in a class template can have default parameters.
Member function instantiation timing in class templates
The timing of member function creation in class templates differs from that in ordinary classes:
- Member functions in ordinary classes are inherently part of the class from the start.
- Member functions in class templates are created only when called.
Example:
class Person1
{
public:
void showPerson1()
{
cout << "Person1 show" << endl;
}
};
class Person2
{
public:
void showPerson2()
{
cout << "Person2 show" << endl;
}
};
template<class T>
class MyClass
{
public:
T obj;
//类模板中的成员函数,并不是一开始就创建的,而是在模板调用时再生成
void fun1() { obj.showPerson1(); }
void fun2() { obj.showPerson2(); }
};
void test01()
{
MyClass<Person1> m;
m.fun1();
//m.fun2();//编译会出错,说明函数调用才会去创建成员函数
}
int main() {
test01();
return 0;
}
Running/Observation Results: After running, the corresponding content will be printed according to the output statements. The variable values can be inferred based on the order of initialization, assignment, and function calls.
Summary: Member functions in class templates are not created at the outset; they are instantiated only when called.
Class template objects as function parameters
Learning Objectives:
- The ways to pass objects instantiated from a class template as arguments to functions.
There are three input methods:
- Specify the type of input directly display the object's data type
- Parameter Templating --- Convert object parameters into templates for passing
- Templatize the entire class --- pass this object type as a template parameter.
Example:
#include <string>
//类模板
template<class NameType, class AgeType = int>
class Person
{
public:
Person(NameType name, AgeType age)
{
this->mName = name;
this->mAge = age;
}
void showPerson()
{
cout << "name: " << this->mName << " age: " << this->mAge << endl;
}
public:
NameType mName;
AgeType mAge;
};
//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)
{
cout << "T的类型为: " << typeid(T).name() << endl;
p.showPerson();
}
void test03()
{
Person <string, int >p("唐僧", 30);
printPerson3(p);
}
int main() {
test01();
test02();
test03();
return 0;
}
Running/Observing the results: After running, the example will print variable values or addresses; address values depend on the runtime environment, so focus on observing the relative positioning and pointer changes of similar objects.
Summary:
- Objects created through class templates can be passed to functions in three ways.
- The more widely used one is the first type: specifying the type passed in.
Class Templates and Inheritance
When class templates encounter inheritance, pay attention to the following points:
- When a subclass inherits from a parent class that is a class template, the subclass must specify the type of T from the parent class when declaring itself.
- If not specified, the compiler is unable to allocate memory for the subclass.
- If you want to flexibly specify the type of T in the base class, the subclass also needs to become a class template. Otherwise, you would be hardcoding the type parameter in the subclass.
For example, this approach fixes the base class's T as int:
class DerivedClass : public BaseClass<int> {
// ...
};
To keep it flexible, you should make the subclass a template:
template <typename T>
class DerivedClass : public BaseClass<T> {
// ...
};
This way, you can specify the type when instantiating the subclass:
DerivedClass<double> obj; // Passes 'double' to the base class's T
Example:
template<class T>
class Base
{
T m;
};
//class Son:public Base //错误,c++编译需要给子类分配内存,必须知道父类中T的类型才可以向下继承
class Son :public Base<int> //必须指定一个类型
{
};
void test01()
{
Son c;
}
//类模板继承类模板 ,可以用T2指定父类中的T类型
template<class T1, class T2>
class Son2 :public Base<T2>
{
public:
Son2()
{
cout << typeid(T1).name() << endl;
cout << typeid(T2).name() << endl;
}
};
void test02()
{
Son2<int, char> child1;
}
int main() {
test01();
test02();
return 0;
}
Running/Observation Results: After running, the corresponding content will be printed according to the output statements. The variable values can be inferred based on the order of initialization, assignment, and function calls.
Summary: If the parent class is a class template, the derived class must specify the data type for the template parameter T in the parent class.
Out-of-Class Implementation of Template Member Functions
Learning Objective: Master the out-of-class implementation of member functions in class templates.
Example:
#include <string>
//类模板中成员函数类外实现
template<class T1, class T2>
class Person {
public:
//成员函数类内声明
Person(T1 name, T2 age);
void showPerson();
public:
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 << "姓名: " << this->m_Name << " 年龄:" << this->m_Age << endl;
}
void test01()
{
Person<string, int> p("Tom", 20);
p.showPerson();
}
int main() {
test01();
return 0;
}
Running/Observing the results: After running, the example will print variable values or addresses; address values depend on the runtime environment, so focus on observing the relative positioning and pointer changes of similar objects.
Summary: When implementing member functions of a class template outside the class, a template parameter list must be added.
Class templates are typically defined in header files due to their nature. Since template definitions must be available at the point of instantiation, common practices include:
- Inclusion model: Placing both template declaration and definition in the same header file (e.g.,
mytemplate.hormytemplate.tppincluded bymytemplate.h) - Explicit instantiation: Defining the template in a source file and explicitly instantiating specific versions there (e.g.,
template class MyClass<int>;)
These approaches ensure the compiler can generate the required code during compilation while maintaining separation of interface and implementation.
Learning Objectives:
- Mastering the issues and solutions related to separating class template member function implementations across files
Question
- The member functions of a class template are instantiated only when called, which can cause linking errors when the code is split across multiple files.
Solution:
- Solution 1: Directly include .cpp source files
- Solution 2: Write both declarations and implementations in the same file, and change the file extension to .hpp. The .hpp extension is a conventional name, not a requirement.
Example:
In the person.hpp file, the code is as follows:
// person.hpp
#ifndef PERSON_HPP
#define PERSON_HPP
#include <string>
class Person {
public:
// Constructor
Person(const std::string& name, int age);
// Destructor
~Person();
// Member functions
void greet() const;
void setName(const std::string& name);
void setAge(int age);
std::string getName() const;
int getAge() const;
private:
std::string name_;
int age_;
};
#endif // PERSON_HPP
#pragma once
#include <iostream>
using namespace std;
#include <string>
template<class T1, class T2>
class Person {
public:
Person(T1 name, T2 age);
void showPerson();
public:
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 << "姓名: " << this->m_Name << " 年龄:" << this->m_Age << endl;
}
Running/Observing the results: After running, the example will print variable values or addresses; address values depend on the runtime environment, so focus on observing the relative positioning and pointer changes of similar objects.
Class template code in the .cpp file
#include<iostream>
using namespace std;
//#include "person.h"
#include "person.cpp" //解决方式1,包含cpp源文件
//解决方式2,将声明和实现写到一起,文件后缀名改为.hpp
#include "person.hpp"
void test01()
{
Person<string, int> p("Tom", 10);
p.showPerson();
}
int main() {
test01();
return 0;
}
Run/Observation Results: This section is syntax definition-focused, typically requiring compilation together with the calling code. Pay attention to the definition method and usage location.
Summary: The mainstream solution is the second approach, which consolidates the class template member functions into a single file and renames the file extension to .hpp.
Class Templates and Friend Functions
Learning Objectives:
- Master the implementation of class templates with friend functions, both inside and outside the class.
Implementation of global function within class - just declare as friend directly inside the class
Implementing global functions outside a class – requires informing the compiler about their existence beforehand via forward declaration.
Example:
#include <string>
//2、全局函数配合友元 类外实现 - 先做函数模板声明,下方在做函数模板定义,在做友元
template<class T1, class T2> class Person;
//如果声明了函数模板,可以将实现写到后面,否则需要将实现体写到类的前面让编译器提前看到
//template<class T1, class T2> void printPerson2(Person<T1, T2> & p);
template<class T1, class T2>
void printPerson2(Person<T1, T2> & p)
{
cout << "类外实现 ---- 姓名: " << p.m_Name << " 年龄:" << p.m_Age << endl;
}
template<class T1, class T2>
class Person
{
//1、全局函数配合友元 类内实现
friend void printPerson(Person<T1, T2> & p)
{
cout << "姓名: " << p.m_Name << " 年龄:" << p.m_Age << endl;
}
//全局函数配合友元 类外实现
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;
};
//1、全局函数在类内实现
void test01()
{
Person <string, int >p("Tom", 20);
printPerson(p);
}
//2、全局函数在类外实现
void test02()
{
Person <string, int >p("Jerry", 30);
printPerson2(p);
}
int main() {
//test01();
test02();
return 0;
}
Running/Observing the results: After running, the example will print variable values or addresses; address values depend on the runtime environment, so focus on observing the relative positioning and pointer changes of similar objects.
Summary: It is recommended to implement global functions within classes for simpler usage, allowing the compiler to directly recognize them.
Class Template Example
Case Description: Implement a generic array class with the following requirements:
- Capable of storing data of both built-in and custom data types.
- Store the data from the array to the heap area.
- You can pass the array's capacity into the constructor.
- Provide the corresponding copy constructor and operator= to prevent shallow copy issues.
- Tail insertion and tail deletion methods are used for adding and removing data from the end of an array.
- You can access array elements using subscript notation.
- You can obtain both the current number of elements and the capacity of an array. This is commonly available in dynamic array implementations (like
std::vectorin C++ orArrayListin Java). The "current number of elements" refers to how many items are actually stored, while the "capacity" is the total space currently allocated, which may be larger to allow for efficient appending of new items.
Example:
The code in myArray.hpp
#pragma once
#include <iostream>
using namespace std;
template<class T>
class MyArray
{
public:
//构造函数
MyArray(int capacity)
{
this->m_Capacity = capacity;
this->m_Size = 0;
pAddress = new T[this->m_Capacity];
}
//拷贝构造
MyArray(const MyArray & arr)
{
this->m_Capacity = arr.m_Capacity;
this->m_Size = arr.m_Size;
this->pAddress = new T[this->m_Capacity];
for (int i = 0; i < this->m_Size; i++)
{
//如果T为对象,而且还包含指针,必须需要重载 = 操作符,因为这个等号不是 构造 而是赋值,
// 普通类型可以直接= 但是指针类型需要深拷贝
this->pAddress[i] = arr.pAddress[i];
}
}
//重载= 操作符 防止浅拷贝问题
MyArray& operator=(const MyArray& myarray) {
if (this->pAddress != NULL) {
delete[] this->pAddress;
this->m_Capacity = 0;
this->m_Size = 0;
}
this->m_Capacity = myarray.m_Capacity;
this->m_Size = myarray.m_Size;
this->pAddress = new T[this->m_Capacity];
for (int i = 0; i < this->m_Size; i++) {
this->pAddress[i] = myarray[i];
}
return *this;
}
//重载[] 操作符 arr[0]
T& operator [](int index)
{
return this->pAddress[index]; //不考虑越界,用户自己去处理
}
//尾插法
void Push_back(const T & val)
{
if (this->m_Capacity == this->m_Size)
{
return;
}
this->pAddress[this->m_Size] = val;
this->m_Size++;
}
//尾删法
void Pop_back()
{
if (this->m_Size == 0)
{
return;
}
this->m_Size--;
}
//获取数组容量
int getCapacity()
{
return this->m_Capacity;
}
//获取数组大小
int getSize()
{
return this->m_Size;
}
//析构
~MyArray()
{
if (this->pAddress != NULL)
{
delete[] this->pAddress;
this->pAddress = NULL;
this->m_Capacity = 0;
this->m_Size = 0;
}
}
private:
T * pAddress; //指向一个堆空间,这个空间存储真正的数据
int m_Capacity; //容量
int m_Size; // 大小
};
Run/Observation Results: This section is syntax definition-focused, typically requiring compilation together with the calling code. Pay attention to the definition method and usage location.
Class template example—Array class encapsulation.cpp
#include "myArray.hpp"
#include <string>
void printIntArray(MyArray<int>& arr) {
for (int i = 0; i < arr.getSize(); i++) {
cout << arr[i] << " ";
}
cout << endl;
}
//测试内置数据类型
void test01()
{
MyArray<int> array1(10);
for (int i = 0; i < 10; i++)
{
array1.Push_back(i);
}
cout << "array1打印输出:" << endl;
printIntArray(array1);
cout << "array1的大小:" << array1.getSize() << endl;
cout << "array1的容量:" << array1.getCapacity() << endl;
cout << "--------------------------" << endl;
MyArray<int> array2(array1);
array2.Pop_back();
cout << "array2打印输出:" << endl;
printIntArray(array2);
cout << "array2的大小:" << array2.getSize() << endl;
cout << "array2的容量:" << array2.getCapacity() << endl;
}
//测试自定义数据类型
class Person {
public:
Person() {}
Person(string name, int age) {
this->m_Name = name;
this->m_Age = age;
}
public:
string m_Name;
int m_Age;
};
void printPersonArray(MyArray<Person>& personArr)
{
for (int i = 0; i < personArr.getSize(); i++) {
cout << "姓名:" << personArr[i].m_Name << " 年龄: " << personArr[i].m_Age << endl;
}
}
void test02()
{
//创建数组
MyArray<Person> pArray(10);
Person p1("孙悟空", 30);
Person p2("韩信", 20);
Person p3("妲己", 18);
Person p4("王昭君", 15);
Person p5("赵云", 24);
//插入数据
pArray.Push_back(p1);
pArray.Push_back(p2);
pArray.Push_back(p3);
pArray.Push_back(p4);
pArray.Push_back(p5);
printPersonArray(pArray);
cout << "pArray的大小:" << pArray.getSize() << endl;
cout << "pArray的容量:" << pArray.getCapacity() << endl;
}
int main() {
//test01();
test02();
return 0;
}
Running/Observing the results: After running, the example will print variable values or addresses; address values depend on the runtime environment, so focus on observing the relative positioning and pointer changes of similar objects.
Summary:
can implement a generic array using the knowledge points learned.