C++ 提高编程

C++ 提高编程,第1张

C++ 提高编程 0.前言

最近在做算法移植的时候,发现自己对c++的知识忘得很多,于是就计划重新捡起来。
纸上得来终觉浅,绝知此事要躬行
一直都是我学习和工作的原则,我比较喜欢动手。
于是我把c++的基础知识一行行代码敲了一遍!

1.模板
1.1 模板的概念

模板就是建立通用的摸具,提高复用性。

模板的特点:

  • 模板不可以直接使用,它只是一个框架
  • 模板的通用不是万能的
1.2 函数模板
  • c++的另一种编程思想称为泛型编程,主要利用的技术就是模板
  • c++提供2种模板机制:函数模板和类模板
1.2.1 函数模板的语法

函数模板的作用:
建立一个统一的函数,其函数返回值类型和形参类型可以不具体,用一个虚拟的类型来代表。

语法:

template
函数声明或者定义
**解释:**
* template ---声明创建模板
* typename --- 表面一种数据类型,可以用class代替
* T --- 通用的数据类型,名字可以随便取,通常为大写字母
template  //或者template 
void mySwap(T &a,T &b)
{
	T temp;
	temp = a;
	a = b;
	b = temp;
}
int main(int argc, char** argv) {
	int a = 10;
	int b = 20;
	//2种方式使用函数模板 
	//1.自动推导类型 
	mySwap(a,b);
	//2.显示指定类型
	mySwap(a,b);
	cout<<"a="< 

2种方式使用函数模板

  • 1.自动推导类型
    mySwap(a,b);
  • 2.显示指定类型
    mySwap(a,b);
1.2.2 函数模板的注意事项

注意事项:

  • 自动类型推导,必须推导出一致的数据类型,才可以使用
template //或者template 
void mySwap(T &a,T &b)
{
	//省略	
} 
void test1()
{
	int a = 10;
	char b = 'c';
	//mySwap(a,b);报错,a和b类型不一致
}
  • 模板必须要确定出T的数据类型,才可以使用
template 
void func()//函数模板 
{
	
}

void test2()
{
	//func();//报错,没指定类型 
	func();//正确 
} 
1.2.3 普通函数和函数模板的区别
  • 普通函数调用时可以发生自动类型转换(隐式类型转换)
  • 函数模板调用时,如果利用自动类型推导,不会发生隐式类型转换
  • 如果利用显示指定类型方式,可以发生显示转换
//普通函数
int add(int a,int b)
{
	cout<
T myAdd(T a,T b)
{
	cout<(a,b);
	return 0;
}
1.2.4 普通函数和函数模板的调用规则
  • 1.如果函数模板和普通函数都可以实现,优先调用普通函数
  • 2.可以通过空模板参数列表来强制调用函数模板
  • 3.函数模板也可以发生重载
  • 4.如果函数模板可以产生更好的匹配,优先调用函数模板。
//普通函数
void myPrint(int a,int b)
{
	cout<<"普通函数 调用"<
void myPrint(T a,T b)
{
	cout<<"函数模板 调用"<
void myPrint(T a,T b,T c)
{
	cout<<"函数模板 重载调用"<(10,20);//强制调用模板函数 
	myPrint(10,20,30);//调用重载的函数模板 
	myPrint('a','b');//函数模板更匹配 
	return 0;
}
1.2.5 模板的局限性

局限性:
模板通用性不是万能的

class Person
{
public:
	Person(string n,int a):name(n),age(a){}
	string name;
	int age;	
} ;

template
bool myCompare(T &a,T &b)
{
	if(a == b)//无法比较Person类 
		return true;
	return false;
}
//利用具体化Person的版本实现代码,具体化优先调用 
template<> bool myCompare(Person &a,Person &b)
{
	if(a.age == b.age && a.name == b.name)
		return true;
	 
	 return false;
}

void test1()
{
	Person p1("Tom",10);
	Person p2("Tom",10);
	myCompare(p1,p2);
}
  • 利用具体化的模板,可以解决自定义类型的通用化
  • 学习模板并不是为了写模板,而是在STL能够运用系统提供的模板
1.3 类模板 1.3.1 类模板语法

类模板的作用:

  • 建立一个通用类,类中的成员数据类型可以不具体指定,用一个虚拟的类型来代表

语法:

template 
template 
class Person
{
public:
	Person(T n,P a):name(n),age(a){}
	T name;
	P age;	
};
int main() {
	Person p1("Tom",10);
	cout< 
1.3.2 类模板与函数模板的区别 
  • 1.类模板没有自动类型推导的使用方式,必须显示指定类型
  • 2.类模板在模板参数列表中可以有默认参数
template //默认整型 
class Person
{
public:
	Person(T n,P a):name(n),age(a){}
	T name;
	P age; 
};
int main(int argc, char** argv) {
	Person p1("tom",10);
	Person p2("tom",10);//<>里面的int可以省略 
	return 0;
}
1.3.3 类模板中 成员函数的创建时机
  • 普通类中的成员函数一开始就可以创建
  • 类模板中的成员函数在调用时才创建
1.3.4 类模板对象做函数参数
  • 1.指定传入的类型 — 直接显示对象的数据类型
  • 2.参数模板化 — 将对象中的参数变为模板进行传递
  • 3.整个类模板化 --将这个对象类型 模板化进行传递
template  
class Person
{
public:
	Person(T n,P a):m_age(a),m_name(n){}
	void showPerson()
	{
		cout<m_name<<" "<m_age< &p)
{
	p.showPerson();
}
void test1() 
{
	Person p1("tom",10);
	printPerson1(p1);
}

//2.参数模板化 
template
void printPerson2(Person &p)
{
	p.showPerson();
}
void test2() 
{
	Person p1("tom2",10);
	printPerson2(p1);
}

//3.整个类模板化 
template
void printPerson3(T &p)
{
	p.showPerson();
}
void test3() 
{
	Person p1("tom3",10);
	printPerson3(p1);
}
1.3.5 类模板与继承
  • 当子继承的父类时一个类模板时,子类在声明的时候,要指定父类中T的类型
  • 如果不指定,编译器无法为子类分配内存
  • 如果想灵活指定父类中T的类型,子类也需要变成类模板
template 
class base
{
public:
	T a;	
};

class Son : public base//指定类型 
{
	
};

template
 class Son2 : public base//灵活指定类型 
 {
 	T1 obj;
 };
1.3.6 类模板成员函数类外实现

类模板中的成员函数类外实现时,需要加上模板参数列表

template 
class Person
{
public:
	Person(T1 n,T2 a);
	void show();
	T1 m_name;
	T2 m_age;
};

template 
Person::Person(T1,T2)
{
	
}

template 
void Person::show()
{
	
}
1.3.7 类模板分文件编写

问题:

  • 类模板成员函数创建时机是在调用阶段,导致分文件编写时链接不到
    解决:
  • 解决方式1:直接包含cpp文件
  • 解决方式2:将声明和实现写到同一个文件红,然后改后缀名为hpp,hpp是约定的名称,非强制!
    Person.h
#include 
#include 
using namespace std;

template 
class Person
{
public:
	Person();
	Person(T1 name,T2 age);
	~Person();
	void showPerson();
	
	T1 name;
	T2 age;
};

Person.cpp

#include "Person.h"


template 
Person::Person(T1 name,T2 age)
{
	this->name = name;
	this->age = age;
}

template 
Person::~Person()
{
}

template 
void Person::showPerson()
{
	cout<main.cpp

  • 解决方式1:直接包含cpp文件 很少这么做
//#include "Person.h" //类模板的成员函数编译时不会创建,因此会找不到引用
#include "Person.cpp" /
void myPrint(int val)
{
	cout< v;
	//2.插入数据
	v.push_back(10);
	v.push_back(20);
	v.push_back(30); 
	//通过迭代器访问
	vector::iterator itBegin = v.begin();//起始迭代器,指向容器第一个元素
	vector::iterator itEnd = v.end();//结束迭代器,指向容器最后一个元素的下一个位置 
	//第一种遍历方式
	while(itBegin != itEnd)
	{
		cout<<*itBegin++<::iterator it = v.begin();it!=v.end();it++)
	{
		cout<<*it< 
2.5.2 vector存放自定义数据类型 
class Person
{
public:
	Person(string n,int a):name(n),age(a){}
	string name;
	int age;	
};

void myPrint(Person p)
{
	cout<name<<" "<age< v;
	Person p1("a",10);
	Person p2("b",20);
	Person p3("c",30);
	Person p4("d",40);
	v.push_back(p1);
	v.push_back(p2);
	v.push_back(p3);
	v.push_back(p4);
	//方式1 遍历 
	for(vector::iterator it = v.begin();it!=v.end();it++)
	{
		cout<<(*it).name<<" "<<(*it).age<name<<" "<age< v;
	Person p1("a",10);
	Person p2("b",20);
	Person p3("c",30);
	Person p4("d",40);
	v.push_back(&p1);
	v.push_back(&p2);
	v.push_back(&p3);
	v.push_back(&p4);
	//方式1 遍历 
	for(vector::iterator it = v.begin();it!=v.end();it++)
	{
		cout<<(*it)->name<<" "<<(*it)->age< 
2.5.3 vector嵌套容器 
//容器嵌套容器
 void test()
 {
 	//1.创建大容器
	 vector> v;
	//2.创建小容器
	vector v1; 
	vector v2; 

	//小容器赋值
	for(int i=0;i<2;i++)
	{
		v1.push_back(i+1);
		v1.push_back(i+1);
		v1.push_back(i+1);
		
		v2.push_back(i+2);
		v2.push_back(i+2);
		v2.push_back(i+2);
	} 
	//大容器赋值
	v.push_back(v1);
	v.push_back(v2);
	//遍历数据
	for(vector>::iterator it = v.begin();it != v.end();it++)
	{
		for(vector::iterator vit = it->begin();vit!=it->end();vit++)
		{
			cout<<*vit<<" ";
		}
		cout< 
3.1 string容器 
3.1.1 string基本概念 

本质:

  • string是c++的字符串,本质上是一个类

string和char*的区别

  • char *是一个指针
  • string是一个类,内部封装了char指针,管理字符串,是一个char类型的容器

特点:
string类内封装了很多成员方法,如find,copy,delete等。
string管理char*所分配的内存,不用担心复制越界和取值越界问题,都类内部进行负责

3.1.2 string构造函数
  • string():创建一个空的字符串,例如string s;
  • string(const char *s):使用字符串s初始化
  • sting(const string& str):使用string对象初始化
  • string(int n,char c):使用n个字符c初始化

省略string的一些内容···

3.2 vector容器 3.2.1 vector基本概念
  • vector数据结构和数组非常相似,也称为单端数组
  • vector可以动态扩展空间,数组是空间是不可变的
  • vector容器的迭代器支持随机访问

动态扩展:

  • 并不是原空间之后申请新的空间,而是找到更大的内存空间,然后将原有数据拷贝到新空间,释放原空间。
3.2.2 vector构造函数

函数原型:

  • vector v:默认构造
  • vector(v.begin(),v.end()):将v.begin()到v.end()中的元素拷贝给自己
  • vector(n,elem):把n个elem拷贝给自己
  • vector(const vector &vec):拷贝构造函数
3.3 deque容器 3.4 stack容器-栈 3.5 queue-队列 3.6 list容器-双向循环链表 3.7 set/multiset容器-二叉树 3.8 map/multimap容器
4.STL-函数对象 4.1 函数对象 4.1.1函数对象的概念

概念

  • 重载函数调用 *** 作符的类,其对象常常称为函数对象
  • 函数对象使用重载的()时,行为类似函数调用,也成为仿函数

本质:
函数对象(仿函数)是一个类,不是函数

4.1.2 函数对象的使用

特点:

  • 函数对象在使用时,可以像普通函数那样调用,可以有参数和返回值
  • 函数对象可以有自己的状态
  • 函数对象可以作为参数传递
class MyAdd
{
public:
	int operator()(int a,int b)
	{
		return a+b;
	}	
} ;
//1. 函数对象在使用时,可以像普通函数那样调用,可以有参数和返回值
void test1()
{
	MyAdd add;
	cout< 
4.2 谓词 
4.2.1 谓词的概念 

概念:

  • 返回bool的类型的仿函数称为 谓词
  • 如果operator()接受1个参数,称为 一元谓词
  • 如果operator()接受2个参数,称为 二元谓词
4.2.2 一元谓词
//1.一元谓词
class GreterFive {
	public:
		bool operator()(int v) {
			return v > 5;
		}
};
void test1() {
	vector v;
	for (int i = 0; i < 10; i++)
		v.push_back(i);
	//查找大于5的值,这里 new GreterFive()是一个匿名对象
	vector::iterator it = find_if(v.begin(), v.end(), GreterFive());
	if (it == v.end()) {
		cout << "没有找到大于5的值" << endl;
	} else {
		cout<<"找到大于5的值:"<<*it< 
4.2.3 二元谓词 
//二元谓词
class Mycompare
{
public:
	bool operator()(int v1,int v2)
	{
		return v1>v2;
	}	
};
void test()
{
	vector v;
	v.push_back(10);
	v.push_back(30);
	v.push_back(20);
	v.push_back(50);
	Mycompare m;
	sort(v.begin(),v.end(),m);
	//sort(v.begin(),v.end(),Mycompare());// Mycompare()是匿名对象 
	for(vector::iterator it = v.begin();it!=v.end();it++)
	{
		cout<<*it<<" ";
	}
	cout< 
4.3 内建函数对象 
4.3.1 概念 

概念:

  • STL内建了一些函数对象
    分类:
  • 算术仿函数
  • 关系仿函数
  • 逻辑仿函数
    用法:
  • 这些仿函数所产生的对象,用法和一般函数完全相同
  • 使用内建函数对象,需要引入头文件
4.3.2 算术仿函数

功能描述:

  • 实现四则运算
  • 其中negate是一元运算,其他都是二元运算

仿函数原型

  • template plus //加法仿函数
  • template minus//减法仿函数
  • template multiplies//乘法仿函数
  • template divides//除法仿函数
  • template modulus //取模仿函数
  • template negate//取反仿函数
//1.取反仿函数 
void test1()
{
	negate n;
	std::cout< p;
	std::cout< 
4.3.3 关系仿函数 

仿函数原型:

  • templatebool equal_to //等于
  • templatebool not_equal_to //不等于
  • templatebool greater //大于
  • templatebool greater_equal //大于等于
  • templatebool less // 小于
  • templatebool less_equal //小于等于
#include 
#include 
#include
#include 
using namespace std; 
void test()
{
	vector v;
	v.push_back(10);
	v.push_back(30);
	v.push_back(40);
	v.push_back(20);

	sort(v.begin(),v.end(),greater());
	for(vector::iterator it= v.begin() ;it!=v.end();it++)
	{
		cout<<*it<<" ";
	} 
	cout< 
4.3.4 逻辑仿函数 

函数原型:

  • template bool logical_and //逻辑与
  • template bool logical_or //逻辑或
  • template bool logical_not //逻辑非

5.STL-常用算法

概述:

  • 算法主要由头文件 、、组成
5.1 常用遍历算法
  • for_each //遍历容器
  • transform //搬运容器到另一个容器中
5.1.1 for_each

函数原型:

  • for_each(iterator beg,iterator end,_func);
//普通函数
void myPrint(int v)
{
	cout< v;
	for(int i=0;i<5;i++)
		v.push_back(i);
	for_each(v.begin(),v.end(),myPrint);
	cout< 
5.1.2 transform 

功能:

  • 将一个容器的内容搬运到另一个容器
    函数原型:
  • transform(iterator beg1,iterator end1,iterator beg2,_func)
    • beg1 源容器开始迭代器
    • end1 源容器结束迭代器
    • beg2 目标容器开始迭代器
    • _func 函数或者函数对象(仿函数)
class MyTransform
{
public:
	int operator()(int v)
	{
		return v;
	}
};

void test()
{
	vector v;
	for(int i=0;i<5;i++)
	{
		v.push_back(i);
	}
	
	vector vTarget;
	vTarget.resize(v.size());//一定要开辟空间,不能用reserve 
	
	transform(v.begin(),v.end(),vTarget.begin(),MyTransform());
	for(vector::iterator it = v.begin();it!=v.end();it++)
	{
		cout<<*it<<" ";
	} 
	cout<::iterator it = vTarget.begin();it!=vTarget.end();it++)
	{
		cout<<*it<<" ";
	} 			
}
5.2 常用的查找算法
  • find
  • find_if
  • adjacent_find
  • binary_search
  • count
  • count_if
5.3常用的排序算法
  • sort
  • random_shuffle 随机打乱元素
  • merge
  • reverse
5.4 常用的拷贝和替换算法
  • copy
  • replace
  • replace_if
  • swap
5.5 常用的算术生成算法

头文件:#include

  • accumulate 计算容器内所有元素的总和
  • fill 向容器内填充元素
5.6 常用的集合算法
  • set_intersection 求两个容器的交集
  • set_union 求两个容器的并集
  • set_difference 求两个容器的差集

继续当一名咸鱼( ̄︶ ̄)!

Stay hungry,Stay foolish!

欢迎分享,转载请注明来源:内存溢出

原文地址: https://outofmemory.cn/zaji/5595295.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-12-15
下一篇 2022-12-15

发表评论

登录后才能评论

评论列表(0条)

保存