The summary of C++ template

The summary of C++ template

This article is a project summary file developed around class templates. We share some details about the use of class templates and easy to ignore when using classes. For example, the member variable of a class is the processing method in the constructor and destructor when it is a pointer variable.

  • Before we go to the code, let's see what we need to do to define this template class: we know that there is a vector dynamic container in the C++ STL standard library, which can dynamically store different types of data, including our custom types, without any problem. This container is very powerful, so today we just use this model to expand the dynamic universal array I want to design. In short, we use the application of C + + class template to realize the universal array that can save int, char, double and custom types. Code without saying more:
#pragma once
//Custom array template class
#include <iostream>
using namespace std;

template <typename T>
class Vector
{
public:
	Vector(int size =128);			//Constructor
	Vector(const Vector &object);	//copy constructor 
	~Vector(void);	//Destructor

	int getSize() const;		//Get the number of elements stored internally
	//vector<int> a1 ,a2,a1[0]
	T& operator[](int index) ;
	//a1=a2=a3
	//[1] Solutions
	template <typename T>
	friend ostream & operator << (ostream & ostr, const Vector<T> &object);
	//[2] Solutions
	//friend ostream & operator << <T>(ostream & ostr, const Vector<T> 
	Vector & operator=(const Vector &object);
private:
	T *m_base;
	int m_len;
};
//template <typename T>
//ostream & operator <<(ostream & ostr,Vector<T> &object);

The above code is the declaration part of the custom Vector class template.

#include "Vector.h"
#include <iostream>
using namespace std;

template <typename T>
Vector<T>::Vector(int size){
	if (size>0){
		this->m_len=size;
		this->m_base=new T[m_len];	//Allocated memory
	}
}
template <typename T>
 Vector<T>::Vector (const Vector &object){
	 this->m_len=object.m_len;
	 this->m_base =new T [m_len];	//[1] Allocate memory space
	 //Data copy
	 for (int i=0;i<m_len;i++){
			this->m_base[i]=object.m_base[i];
	 }

}	//copy constructor 

template <typename T>
Vector<T>::~Vector(void){
	if (m_base!=NULL){
		delete [] m_base;
		m_base=NULL;
		m_len=0;
	}
}
template <typename T>
T& Vector<T>:: operator[](int index) {
	return m_base[index];
}
template <typename T>
Vector<T> & Vector<T>:: operator=(const Vector &object){
	if (m_base!=NULL){
		delete [] m_base;
		m_base=NULL;
		m_len=0;
	} 
	this->m_len=object.m_len;
	this->m_base =new T [m_len];	//[1] Allocate memory space
	//This - > m_base = (t *) malloc (m_len); / / [2] memory allocation of c language in the second
	//Data copy
	for (int i=0;i<m_len;i++){
		this->m_base[i]=object.m_base[i];
	}
	return *this;
}
template <typename T>
int  Vector<T>::getSize() const{
	return m_len;
}

//Using global friend function to realize the overload of < output stream operator
template <typename T>
ostream & operator <<(ostream & ostr, const Vector<T> &object){

	for (int i=0;i<object.m_len;i++){
		ostr<<object.m_base[i]<<"\t";
	}
	ostr<<endl;
	return ostr;
}

This is the implementation code of the template. In fact, the principle is very simple. Create a dynamic memory in the template class to save the data from different types, and then extract the data from this memory. Let's take a look at the implementation output and it's almost understandable.

#include <Windows.h>
#include <iostream>
#include "Vector.hpp"
#include "Vector.h"
using namespace std;

int main(){
	Vector <float> myVetor(10);
	for (int i =0;i<myVetor.getSize();i++){
		myVetor[i]=i*0.1f;
		cout<<myVetor[i]<<endl;
	}
	Vector <float> aVetor;
	aVetor=myVetor;
	cout<<"heavy load=Output of symbols"<<endl;
	for (int i =0;i<aVetor.getSize();i++){
		cout<<aVetor[i]<<endl;
	}
	Vector <float> mty(myVetor);
	cout<<"Output of copy constructor"<<endl;
	for (int i =0;i<mty.getSize();i++){
		cout<<mty[i]<<endl;
	}
	cout<<myVetor<<mty;
	system("pause");
	return 0;
}

Output results:

In fact, this has completed 50% of the universal array. The most important thing is how to bring the custom type to it!
We might as well create a user-defined Student class as follows:

#pragma once
#include <string>
using namespace  std;
class Student{
public:
	Student();
	Student(const char* name ,int age=0);
	Student (const Student &object);			//User-Defined Copy Constructor 
	Student& operator= (const Student &other );	//Overloaded assignment constructor
	string getStr() const;
	~Student(void);
private:
	int age;		//Age
	char *name;		//Full name
	//string name;
};

Implementation file of Student class

#include "Student.h"
#include <sstream>
using namespace std;

Student::Student(){
	this->age=0;
	this->name="Unnamed";
	const  char * defaultName="Unnamed";
	this->name=(char*)malloc((strlen(defaultName)+1)*sizeof(char));
	strcpy_s(this->name,strlen(defaultName)+1,defaultName);
}

Student& Student:: operator= (const Student & other ){
	this->name=(char*)malloc((strlen(other.name)+1)*sizeof(char));
	strcpy_s(this->name,strlen(other.name)+1,other.name);

	this->age=other.age;

	return *this;
}
Student:: Student (const Student &object){
	if (name){
		delete name;
	}
	this->name=(char*)malloc((strlen(object.name)+1)*sizeof(char));
	strcpy_s(this->name,strlen(object.name)+1,object.name);
	this->age=object.age;

}	//User-Defined Copy Constructor 
Student:: Student(const  char* name ,int age){
	int len=strlen(name)+1 ;
	this->name=(char*)malloc(len*sizeof(char));  //Dynamic memory allocation
	strcpy_s(this->name,len,name);
	//this->name=name;
	this->age=age;
}

Student::~Student(void){
	if (name){
		delete name;
		/*free(name);*/
	}
}
string Student:: getStr() const{
	stringstream sstr;
	sstr<<"Full name:"<<name<<"\t Age:"<<age<<endl;
	return  sstr.str();
}

You can see that in several constructors of the class, the malloc() function (of course, you can also use the new keyword to apply for memory space) is used to create a new memory space to save the name information. Why?
Here are two points to note:

  • Why do we need to customize copy constructor and assignment constructor? We know that the system will automatically generate "composite assignment constructor" and "composite copy constructor" for us when copying and assigning objects. Of course, I didn't care about running directly at the beginning and found that the system could not exit normally at all. Only after repeated debugging can we find out the root problem, which is caused by calling the default constructor. Does it sound like nonsense.
  • So why don't we have this problem without pointer variables?

It's not hard to know. That's Debug. It's so simple. We annotated the custom assignment constructor to see what happens. After exiting, an interrupt is triggered. Let's click Retry. Don't click abort. Then you won't see anything! Remember to click Retry to trigger the interrupt

This is the test code:

	Student stu1("Xiao Hua Wang",30);
	Student stu2("Da Wei Wang",21);
	//Put the class in a custom container
	Vector <Student> stuList(2);
	stuList[0]=stu1;
	stuList[1]=stu2;
	for(int i=0;i<stuList.getSize();i++){
		cout<<stuList[i].getStr();   
	}
	vector<Student>stuList1;
	stuList1.push_back(stu1);
	stuList1.push_back(stu2);
	for(unsigned int i=0; i<stuList1.size();i++){
		cout<< stuList1[i].getStr();
	}

Click [retry] to pop up the dialog box: click [interrupt] to see where the problem is.
Don't look at anything, because you can't understand the location of the breakpoint. Just look at the content in the call stack. Of course, it's not all about clicking to jump to our own code location to see what's wrong? You can see a location like Student::~Student(). Check it out.

The code is out of order. It's not the original name. Is it not the original thing that the object finds the memory to be released when it is destructed? This is a very dangerous operation. How can the system let you simply release it?
In fact, the problem is that stuList[0]=stu1.
In this sentence, the class's assignment constructor is called. The problem is that the default assignment constructor is a simple bit copy, which is called a shallow copy. A simple shallow copy has no great impact on general data, but for pointer variables, that is, to destroy the sky and destroy the earth. Imagine that you use the middle pointer of another object, let alone modify it, What's more, you give something to others. Where can you find this thing after he releases his memory? It's a never-ending operation. You can't find it anywhere. The memory you found has been used by others. Even if no one is using it, you can't use it freely! Is it embarrassing? In order to avoid this phenomenon, we need to make a deep copy like the above code, create a new memory for the assigned object to save the pointer variable, so that the above problems will not occur.
Student::~Student(void){
if (name){
delete name;
/free(name);/
}
}

Similar to the above problem: stulist1.push back (stu1) when using the vector container; here we will use the copy constructor to see the prototype of the push back() function. The treatment is similar to the above.

That's about it.

Published 3 original articles, won 3 praises, and visited 31
Private letter follow

Keywords: Windows C

Added by johnsmith153 on Tue, 25 Feb 2020 14:33:50 +0200