C++提高编程(黑马笔记)

时间:2024-03-01 22:49:30

C++提高编程

模版

特点:

  • 只是一个框架,不可以直接使用
  • 通用并不是万能的

泛型主要利用模版

函数模版

语法:

template<typename T>
函数
# include<iostream>
using namespace std;

template<typename T>
void MySwap(T& a, T& b) {
	T temp = a;
	a = b;
	b = temp;
}

void test01() {
	int a = 10;
	int b = 20;
	MySwap(a, b);
	cout << a << " " << b << endl;
	char c = 'a';
	char d = 'b';
	MySwap<char>(c, d);
	cout << c << " " << d << endl;
}

int main() {
	test01();
	system("pause");
	return 0;
}

注意事项:

  • 自动类型推导,必须推导出一致的数据类型T,才可以使用
  • 模版必须确定出T的数据类型才可以使用
# include<iostream>
using namespace std;

template<typename T>
void MySwap(T& a, T& b) {
	T temp = a;
	a = b;
	b = temp;
}

template<class T>
void func() {
	cout << "func" << endl;
}

void test01() {
	int a = 10;
	int b = 20;
	MySwap(a, b);
	char c = 'a';
	//MySwap(c, a);
	//func();
	func<int>();
}

int main() {
	test01();
	system("pause");
	return 0;
}

普通函数与函数模版的区别:

  • 普通函数可以发生自动类型转换
  • 函数模版调用时,如果利用自动类型推导,不会发生自动类型转换
  • 如果利用显示指定类型的方式,可以发生自动类型转换
# include<iostream>
using namespace std;

template<typename T>
T MyAdd1(T a, T b) {
	return a + b;
}

int MyAdd2(int a, int b) {
	return a + b;
}

void test01() {
	int a = 10;
	int b = 20;
	char c = 'a'; // 97
	int ans = 0;
	ans = MyAdd2(a, c);
	cout << ans << endl;
	//ans = MyAdd1(a, c);
	ans = MyAdd1<int>(a, c);
	cout << ans << endl;
}

int main() {
	test01();
	system("pause");
	return 0;
}

普通函数与函数模版的调用规则:

  1. 都可实现,优先调用普通函数
  2. 可以通过空模版参数列表来强制调用函数模版
  3. 函数模版也可以重载
  4. 如果函数模版可以更好的匹配,优先调用函数模版
# include<iostream>
using namespace std;

void MySwap(int &a, int &b) {
	cout << "普通函数" << endl;
}

template<typename T>
void MySwap(T &a, T &b) {
	cout << "函数模版" << endl;
}

template<typename T>
void MySwap(T& a, T& b, int x) {
	cout << "重载函数模版" << endl;
}

void test01() {
	int a = 10;
	int b = 2;
	MySwap(a, b);
	MySwap<>(a, b);
	MySwap(a, b, 100);
	char c = 'a';
	char d = 'b';
	MySwap(c, d);
}

int main() {
	test01();
	system("pause");
	return 0;
}

局限性:

  • 传入class类时,需要进行函数模版的重载
# include<iostream>
# include<string>
using namespace std;

class Person {
public:
	Person(string name, int age) {
		this->m_name = name;
		this->m_age = age;
	}
	string m_name;
	int m_age;
};

template<typename T>
bool MyCompare(T &a, T &b) {
	if (a == b) {
		return true;
	}
	return false;
}


template<> bool MyCompare(Person & a, Person & b) {
	if (a.m_age == b.m_age && a.m_name == b.m_name) {
		return true;
	}
	return false;
}

void test01() {
	Person p1("张三", 19);
	Person p2("罗向", 55);
	Person p3("张三", 19);
	if (MyCompare(p1, p2)) {
		cout << "p1 p2 一样" << endl;
	}
	else {
		cout << "p1 p2 不一样" << endl;
	}
	if (MyCompare(p1, p3)) {
		cout << "p1 p3 一样" << endl;
	}
	else {
		cout << "p1 p3 不一样" << endl;
	}
}

int main() {
	test01();
	system("pause");
	return 0;
}

类模版

语法:

template<typename T>
# include<iostream>
# include<string>
using namespace std;

template <class NameType, class AgeType>
class Person {
public:
	Person(NameType name, AgeType age) {
		this->m_name = name;
		this->m_age = age;
	}
	void show() {
		cout << m_name << " " << m_age << endl;
	}
	NameType m_name;
	AgeType m_age;
};

void test01() {
	Person<string, int> p("孙悟空", 999);
	p.show();
}

int main() {
	test01();
	system("pause");
	return 0;
}

类模版与函数模版区别:

类模版与函数模版区别主要有两点:

  1. 类模版没有自动类型推导的使用方式
  2. 类模版在模版参数列表中可以有默认参数
# include<iostream>
# include<string>
using namespace std;

template <class NameType, class AgeType = int>
class Person {
public:
	Person(NameType name, AgeType age) {
		this->m_name = name;
		this->m_age = age;
	}
	void show() {
		cout << m_name << " " << m_age << endl;
	}
	NameType m_name;
	AgeType m_age;
};

void test01() {
	//Person p("孙悟空", 999);
	Person<string> p("财务科", 98);
	p.show();
}

int main() {
	test01();
	system("pause");
	return 0;
}

类模版中成员函数创建时机:

  • 普通类中成员函数一开始就可以创建
  • 类模版中成员函数在调用时才创建
# include<iostream>
# include<string>
using namespace std;

class Person1 {
public:
	void show1() {
		cout << 1 << endl;
	}
};

class Person2 {
public:
	void show2() {
		cout << 2 << endl;
	}
};

template<class T>
class MyClass {
public:
	T obj;
	void func1() {
		obj.show1();
	}
	void func2() {
		obj.show2();
	}
};

void test01() {
	MyClass<Person1> c;
	c.func1();
	//c.func2();
}

int main() {
	test01();
	system("pause");
	return 0;
}

类模版对象做函数参数:

三种传入方式:

  1. 指定传入的类型(直接显示对象的数据类型)
  2. 参数模版化(将对象中的参数变为模版进行传递)
  3. 整个类模版化(将这个对象类型 模版化进行传递)
# include<iostream>
# include<string>
using namespace std;

template<class T1, class T2>
class Person {
public:
	Person(T1 name, T2 age) {
		this->m_name = name;
		this->m_age = age;
	}
	void showPerson() {
		cout << m_name << " " << m_age << endl;
	}
	T1 m_name;
	T2 m_age;
};

void show1(Person<string, int> &p) {
	p.showPerson();
}

template<class T1, class T2>
void show2(Person<T1, T2> &p) {
	p.showPerson();
}

template<class T> 
void show3(T& p) {
	p.showPerson();
}

void test01() {
	Person<string, int> p("孙悟空", 999);
	show1(p);
	show2(p);
	show3(p);
}

int main() {
	test01();
	system("pause");
	return 0;
}

类模版与继承:

注意事项:

  • 当子类继承的父类是一个类模版时,子类在声明的时候,要指定出父类中的T类型
  • 如果不指定,编译器无法给子类分配内存
  • 如果想灵活指定出父类中T的类型,子类也虚变为类模版
# include<iostream>
# include<string>
using namespace std;

template<class T> 
class Base {
public:
	T m;
};

class Son1 : public Base<int> {

};

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

void test01() {
	Son2<int, char> s2;
}

int main() {
	test01();
	system("pause");
	return 0;
}

类模版成员函数类外实现:

# include<iostream>
# include<string>
using namespace std;

template<class T1, class T2>
class Person {
public:
	Person(T1 name, T2 age);
	void showPerson();
	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 << m_name << " " << m_age << endl;
}

void test01() {
	Person<string, int> p("猪八戒", 888);
	p.showPerson();
}

int main() {
	test01();
	system("pause");
	return 0;
}

类模版分文件编写:

问题:类模版中成员函数创建时机是在调用阶段,导致分文件编写时链接不到

解决:

  • 直接包含.cpp源文件
  • 将声明和实现写到同一个文件中,更改后缀名为.hpp

person.h

#pragma once
# include<iostream>
# include<string>
using namespace std;

template<class T1, class T2>
class Person {
public:
	Person(T1 name, T2 age);
	void showPerson();
	T1 m_name;
	T2 m_age;
};

person.cpp

#include "person.h"
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 << m_name << " " << m_age << endl;
}

main.cpp

# include<iostream>
# include<string>
# include "person.cpp"
using namespace std;

void test01() {
	Person<string, int> p("猪八戒", 888);
	p.showPerson();
}

int main() {
	test01();
	system("pause");
	return 0;
}

person.hpp

#pragma once
# include<iostream>
# include<string>
using