模板函数
#define _CRT_SECURE_NO_WARNINGS
#include "iostream"
#include <algorithm>
#include <vector>
using namespace std;
template <typename T>
void myswap(T& t, T& t2) {
T temp = t;
t = t2;
t2 = temp;
cout << "t=" << t << " t2=" << t2 << endl;;
}
void method() {
int a = 1, b = 2;
myswap<int>(a, b);
myswap(a, b);//自动类型推导
char c = 'c';
char d = 'd';
myswap(c, d);
float e = 1.2f;
float f = 32.3f;
myswap<float>(e, f);
}
void main() {
method();
system("pause");
}
模板类
#define _CRT_SECURE_NO_WARNINGS
#include "iostream"
#include <algorithm>
#include <vector>
using namespace std;
template <typename R>
class C {
public:
C(R r) {
this->r = r;
}
void printR() {
cout<<r<<endl;
}
public:
R r;
};
void main() {
C<int> c(12);
c.printR();
C<float> d(12.3f);
d.printR();
system("pause");
}
//模板类派生普通类
#define _CRT_SECURE_NO_WARNINGS
#include "iostream"
#include <algorithm>
#include <vector>
using namespace std;
template <typename R>
class C {
public:
C(R r) {
this->r = r;
cout << "C(R r) :" << r << endl;
}
void printR() {
cout<<r<<endl;
}
public:
R r;
};
class B :public C<int> {
public:
B(int c) :C<int>(c){
cout <<"B(int c) :"<< c << endl;
}
int b;
};
void main() {
C<int> c(12);
c.printR();
C<float> d(12.3f);
d.printR();
B b(45);
system("pause");
}
//模板类派生模板类
#define _CRT_SECURE_NO_WARNINGS
#include "iostream"
#include <algorithm>
#include <vector>
using namespace std;
template <typename R>
class C {
public:
C(R r) {
this->r = r;
cout << "C(R r) :" << r << endl;
}
void printR() {
cout<<r<<endl;
}
public:
R r;
};
template <typename Z>
class B :public C<Z> {
public:
B(Z c) :C<Z>(c){
cout <<"B(int c) :"<< c << endl;
}
Z b;
};
void main() {
B<int> b(45);
system("pause");
}
函数模板和友元函数
注意,只在重载左移右移运算符的时候使用友元函数,其他都不要用,友元函数容易导致问题
#define _CRT_SECURE_NO_WARNINGS
#include "iostream"
#include <algorithm>
#include <vector>
using namespace std;
template <typename T>
class Complex {
public:
T a;
T b;
Complex(T a, T b) {
this->a = a;
this->b = b;
}
//友元函数如果函数体写在类外边,那么T拿不到,所以只能这样
friend ostream& operator<<(ostream& o, Complex<T> c) {
o << c.a << " " << c.b << endl;
return o;
}
Complex& operator+(Complex &c) {
Complex temp(a + c.a, b + c.b);
return temp;
}
void print() {
cout << a << " " << b << endl;
}
};
void main() {
Complex<int> c1(1, 2);
Complex<int> c2(3, 4);
Complex<int> c3 = c1 + c2;
c3.print();
cout << c3 << endl;
system("pause");
}
传引用和传对象的区别
#define _CRT_SECURE_NO_WARNINGS
#include "iostream"
#include <algorithm>
#include <vector>
using namespace std;
template <typename T>
class Complex {
public:
T a;
T b;
Complex(T a, T b) {
this->a = a;
this->b = b;
}
Complex(Complex& c) {
a = c.a;
b = c.b;
cout << "拷贝构造函数执行 " <<a<<" "<<b<< endl;
}
};
//传对象有一个赋值过程,会走拷贝构造函数,相当于
//Complex b(12,3);
//Complex c = b;
void method(Complex<int> c) {
cout<<c.a<<" "<<c.b<<endl;
}
//传引用不会走拷贝构造函数
void method2(Complex<int> &c) {
cout << c.a << " " << c.b << endl;
}
void main() {
Complex<int> c1(1, 2);
method(c1);
system("pause");
}
函数声明写在类内部,实现写在类外部
编译通过,但是运行你会发现其他方法都可以,唯独友元函数这样实现报错
严重性 代码 说明 项目 文件 行 禁止显示状态
错误 LNK2019 无法解析的外部符号 "class std::basic_ostream<char,struct std::char_traits<char> > & __cdecl operator<<(class std::basic_ostream<char,struct std::char_traits<char> > &,class Complex<int>)" (??6@YAAAV?char_traits@D@std@@@std@@AAV01@V?$Complex@H@@@Z),该符号在函数 _main 中被引用 Project1 C:\Users\Administrator\source\repos\Project1\Project1\helloworld.obj 1
需要在友元函数的声明后加上泛型T
#define _CRT_SECURE_NO_WARNINGS
#include "iostream"
#include <algorithm>
#include <vector>
using namespace std;
template <typename T>
class Complex {
public:
T a;
T b;
Complex(T a, T b);
//friend ostream& operator<<(ostream& o, Complex<T> c);//错误
friend ostream& operator<<<T>(ostream& o, Complex<T> c);//正确
Complex& operator+(Complex& c);
void print();
};
template <typename T>
Complex<T>::Complex(T a, T b) {
this->a = a;
this->b = b;
}
template <typename T>
void Complex<T>::print() {
cout << a << " " << b << endl;
}
template <typename T>
Complex<T>& Complex<T>::operator+(Complex<T>& c) {
Complex<T> temp(a + c.a, b + c.b);
return temp;
}
template <typename T>
ostream& operator<<(ostream& o, Complex<T> c) {
o << c.a << " " << c.b << endl;
return o;
}
void main() {
Complex<int> c1(1, 2);
Complex<int> c2(3, 4);
Complex<int> c3 = c1 + c2;
c3.print();
cout << c3 << endl;
system("pause");
}
类的声明在.h文件中,类的实现在.cpp文件中时,
test.h
#pragma once
#define _CRT_SECURE_NO_WARNINGS
#include "iostream"
#include <algorithm>
#include <vector>
using namespace std;
template <typename T>
class Complex {
public:
T a;
T b;
Complex(T a, T b);
friend ostream& operator<<<T>(ostream& o, Complex<T> c);
Complex& operator+(Complex& c);
void print();
};
test.cpp
#include"test.h"
template <typename T>
Complex<T>::Complex(T a, T b) {
this->a = a;
this->b = b;
}
template <typename T>
void Complex<T>::print() {
cout << a << " " << b << endl;
}
template <typename T>
Complex<T>& Complex<T>::operator+(Complex<T>& c) {
Complex<T> temp(a + c.a, b + c.b);
return temp;
}
template <typename T>
ostream& operator<<(ostream& o, Complex<T> c) {
o << c.a << " " << c.b << endl;
return o;
}
main.cpp
//当你的类中使用了类模板,类的声明在.h文件中,类的实现在.cpp文件中时,
//引入类时通过#include "test.h"是不行的,会报错,正确的方式是引入cpp文件
//这也是为什么有些库中会出现hpp文件的原因,就是把声明和实现写在同一个类中
//#include "test.h"
#include "test.cpp"
void main() {
Complex<int> c1(1, 2);
Complex<int> c2(3, 4);
Complex<int> c3 = c1 + c2;
c3.print();
cout << c3 << endl;
system("pause");
}
模板函数中的static变量
static 属于整个程序,但是当在模板中使用,他就属于当前模板类型的对象,如下程序从打印结果可以看出,两个static是没有关联的
#pragma once
#define _CRT_SECURE_NO_WARNINGS
#include "iostream"
using namespace std;
template <typename T>
class Complex {
public:
static T c;
};
template <typename T>
T Complex<T>::c = 100;
void main() {
Complex<int> c1;
Complex<char> c2;
c1.c++;
c1.c++;
c1.c++;
c2.c++;
c2.c++;
c2.c++;
cout<<c1.c<<endl;
cout<<c2.c<<endl;
system("pause");
}
打印结果
103
g
请按任意键继续. . .
使用类泛型模板实现数组操作,要求实现数组通用属性[],=,cout<<
头文件
#pragma once
#include <iostream>
using namespace std;
template <typename T>
class MyVector
{
public:
MyVector(int size = 0);
MyVector(const MyVector& v);
~MyVector();
public:
//[]
T& operator[](int index);
//=
MyVector &operator=(MyVector& v);
//<<
friend ostream& operator<< <T>( ostream& cout,MyVector& v);
public:
T* m_space;
int m_len;
};
源文件
#include "MyVector.h"
template <typename T>
MyVector<T>::MyVector(int size) {
m_space = new T[size];
m_len = size;
}
template <typename T>
MyVector<T>::MyVector(const MyVector<T>& v) {
m_len = v.m_len;
m_space = new T[m_len];
for (int i = 0; i < m_len; i++) {
m_space[i] = v.m_space[i];
}
}
template <typename T>
MyVector<T>::~MyVector() {
if (m_space != NULL) {
delete[]m_space;
m_space = NULL;
m_len = 0;
}
}
template <typename T>
T& MyVector<T>::operator[](int index) {
return m_space[index];
}
template <typename T>
MyVector<T>& MyVector<T>::operator=(MyVector<T>& v) {
//先释放原有内存
if (m_space != NULL) {
delete[]m_space;
m_space = NULL;
m_len = 0;
}
//再分配新的内存
m_len = v.m_len;
m_space = new T[m_len];
//拷贝数据
for (int i = 0; i < m_len; i++) {
m_space[i] = v[i];
}
return *this;
}
template <typename T>
ostream& operator<<(ostream& cout, MyVector<T>& v){
for (int i = 0; i < v.m_len; i++) {
cout << v.m_space[i] << " ";
}
cout << endl;
return cout;
}
调用端
#pragma once
#define _CRT_SECURE_NO_WARNINGS
#include "iostream"
#include "MyVector.cpp"
void main() {
MyVector<int> vector(10);
cout << "使用[]给数组赋值" << endl;
for (int i = 0; i < vector.m_len; i++) {
vector[i] = i + 1;
cout << vector[i]<<" ";
}
cout<<endl;
cout << "使用=号实现数组拷贝" << endl;
MyVector<int> v2 = vector;
for (int i = 0; i < v2.m_len; i++) {
cout << v2[i]<<" ";
}
cout << endl;
cout << "使用<<输出整个数组" << endl;
cout << v2 << endl;
system("pause");
}
数组保存对象
还是用上边的MyVector数组,添加自定义对象,这个对象要满足一些条件
a.实现拷贝构造函数,避免浅拷贝问题
b.重载等号=运算符,因为数组要通过arr[i] = obj赋值
c.重载<<运算符,因为cout<<arr应该可以打印数组元素
d.析构函数,保证数据正常销毁
e.有参构造和无参构造都要添加
拷贝构造函数和=号运算符的执行时机:
拷贝构造函数是在对象未分配内存之前通过=号赋值时执行
而重载=号运算符是在对象已经分配内存后,重新赋值时会执行,可以看main方法中的执行
虽然两者都使用了=号,但是执行时机不同,这也是为什么拷贝构造函数不需要释放内存的原因,因为他执行前并没有分配内存
#define _CRT_SECURE_NO_WARNINGS
#include "iostream"
#include "MyVector.cpp"
class Teacher {
public:
int age;
char* name;
Teacher() {
this->age = 0;
name = new char[1];
strcpy(name, "");
}
Teacher(int age, const char* n) {
this->age = age;
//注意:char数组以0为结尾,所以必须添加一个长度,否则报错
name = new char[strlen(n) + 1];
strcpy(name, n);
cout << "构造函数执行:name=" << name << ",age =" << age << endl;
}
Teacher(const Teacher& t) {
//拷贝构造函数不需要执行这一步(重载=号需要)
//为什么?这和二者的执行时机有关,拷贝构造函数是在对象未分配内存之前通过=号赋值时执行
//而重载=号运算符是在对象已经分配内存后,重新赋值时会执行,可以看main方法中的执行
//虽然两者都使用了=号,但是执行时机不同,这也是为什么拷贝构造函数不需要释放内存的原因
//因为他执行前并没有分配内存
//if (name != NULL) {
// delete[]name;
// name = NULL;
// age = 0;
//}
age = t.age;
//注意:char数组以0为结尾,所以必须添加一个长度,否则报错
name = new char[strlen(t.name) + 1];
strcpy(name, t.name);
cout << "拷贝构造函数执行:name=" << name << ",age =" << age << endl;
}
~Teacher() {
if (name != NULL) {
delete[]name;
name = NULL;
age = 0;
}
cout << "析构函数执行" << endl;
}
friend ostream& operator<<(ostream& cout, Teacher& t) {
cout << "<<函数执行teacher name=" << t.name << " teacher age=" << t.age << endl;
return cout;
}
Teacher& operator=(Teacher& t) {
if (name != NULL)
{
delete[]name;
name = NULL;
age = 0;
}
//注意:char数组以0为结尾,所以必须添加一个长度,否则报错
name = new char[strlen(t.name) + 1];
strcpy(name, t.name);
age = t.age;
cout << "等号函数执行:name=" << name << ",age =" << age << endl;
return *this;
}
void print() {
cout << "name = " << name << ",age = " << age << endl;
}
};
void method() {
MyVector<Teacher> v(3);
Teacher t(12, "小明");
Teacher t2(13, "张三");
Teacher t3(14, "李四");
v[0] = t;
v[1] = t2;
v[2] = t3;
Teacher temp = t;
Teacher temp2 = t2;
Teacher temp3 = t3;
for (int i = 0; i < v.m_len; i++) {
cout << v[i] << " ";
}
}
void main() {
method();
system("pause");
}
打印结果:
构造函数执行:name=小明,age =12
构造函数执行:name=张三,age =13
构造函数执行:name=李四,age =14
等号函数执行:name=小明,age =12
等号函数执行:name=张三,age =13
等号函数执行:name=李四,age =14
拷贝构造函数执行:name=小明,age =12
<<函数执行teacher name=小明 teacher age=12
<<函数执行teacher name=张三 teacher age=13
<<函数执行teacher name=李四 teacher age=14
析构函数执行
析构函数执行
析构函数执行
析构函数执行
析构函数执行
析构函数执行
析构函数执行
请按任意键继续. . .
网友评论