上次学习C++还是好几年以前的事,最近用的一直都是python,cpp除了C以外的用法几乎全忘了。即将开始准备明年2月的暑期实习,打算用C++写算法,所以刷力扣前就先来复习下C++吧。python随意,C++古板,但实际上各有优劣。
简洁易懂的C++教程先过一遍:https://www.runoob.com/cplusplus/cpp-tutorial.html
基础的语法就不在笔记里回顾了,脑子里过一遍for,while,if,int,float,double,int *.... 每个变量都要先声明再使用!别忘记加分号!(Java,Python不需要加)
总结出自己不太熟练的用法,包括:模板、STL、类的继承、指针和C++11新特性,共5部分。
以下笔记参考:https://www.runoob.com/cplusplus/cpp-templates.html
C++模板分为两种:函数模板,类模板。为什么需要模板?目的就是一般化、可重复使用!
1.泛型编程(来自百度百科)
泛型可理解为:不与任何特定数据结构或对象类型系在一起。
泛型好处:
(1)编译时的严格类型检查。这是集合框架最重要的特点。
(2)泛型消除了绝大多数的类型转换。如果没有泛型,当你使用集合框架时,你不得不进行类型转换。
关于泛型的理解可以总结下面的一句话,它是把数据类型作为一种参数传递进来。
泛型编程(Generic Programming)最初提出时的动机很简单直接:发明一种语言机制,能够帮助实现一个通用的标准容器库。所谓通用的标准容器库,就是要能够做到,比如用一个List类存放所有可能类型的对象这样的事;泛型编程让你编写完全一般化并可重复使用的算法,其效率与针对某特定数据类型而设计的算法相同。泛型即是指具有在多种数据类型上皆可操作的含义,与模板有些相似。STL巨大,而且可以扩充,它包含很多计算机基本算法和数据结构,而且将算法与数据结构完全分离,其中算法是泛型的,不与任何特定数据结构或对象类型系在一起。
STL是一种泛型编程。面向对象编程关注的是编程的数据方面,而泛型编程关注的是算法。它们之间的共同点是抽象和创建可重用代码,但它们的理念截然不同。
泛型编程最初诞生于C++中,目的是为了实现C++的STL(标准模板库)。其语言支持机制就是模板(Templates)。模板的精神其实很简单:参数化类型。换句话说,把一个原本特定于某个类型的算法或类当中的类型信息抽掉,抽出来做成模板参数T。
2.模板
模板是泛型编程的基础,泛型编程即以一种独立于任何特定类型的方式编写代码。
模板是创建泛型类或函数的蓝图或公式。库容器,比如迭代器和算法,都是泛型编程的例子,它们都使用了模板的概念。
每个容器都有一个单一的定义,比如 向量,我们可以定义许多不同类型的向量,比如 vector <int> 或 vector <string>。
您可以使用模板来定义函数和类,接下来让我们一起来看看如何使用。
函数模板
模板函数定义的一般形式如下所示:
template <typename type> ret-type func-name(parameter list)
{
// 函数的主体
}
在这里,type 是函数所使用的数据类型的占位符名称。这个名称可以在函数定义中使用。
下面是函数模板的实例,返回两个数中的最大值:
//实例
#include <iostream>
#include <string>
using namespace std;
template <typename T>
inline T const& Max (T const& a, T const& b)
{
return a < b ? b:a;
}
int main ()
{
int i = 39;
int j = 20;
cout << "Max(i, j): " << Max(i, j) << endl;
double f1 = 13.5;
double f2 = 20.7;
cout << "Max(f1, f2): " << Max(f1, f2) << endl;
string s1 = "Hello";
string s2 = "World";
cout << "Max(s1, s2): " << Max(s1, s2) << endl;
return 0;
}
Max(i, j): 39
Max(f1, f2): 20.7
Max(s1, s2): World
这样,无论待比较的两个数是什么类型float/string/int,都能用这样一种通用的函数进行同样的处理。
查漏补缺:const的神奇用法
T const& a
T可以看做任何一种数据类型,比如int。int const& a,表示变量a是另一个int类型的常量的引用。
const表示常量,不可修改;&表示引用,内存地址相同;const&表示某种数据类型常量的引用。
int max() const{...}
常函数不对对象的任何成员数据的进行修改(最常见的为打印成员信息的函数),那么我们可以将这个成员函数设置为const函数,以保护对象数据。如void print()const 对成员函数()后加上const限定 如果在该函数里面修改对象的成员数据,则编译器就会报错。const是一种保护措施!
c++ 函数前面和后面 使用const 的作用:
- 前面使用const 表示返回值为const
- 后面加 const表示函数不可以修改class的成员,理解为“只读”函数
参考:
https://blog.csdn.net/zha_ojunchen/article/details/82561813
类模板
正如我们定义函数模板一样,我们也可以定义类模板。泛型类声明的一般形式如下所示:
template <class type> class class-name {
.
.
.
}
在这里,type 是占位符类型名称,可以在类被实例化的时候进行指定。您可以使用一个逗号分隔的列表来定义多个泛型数据类型。
下面的实例定义了类 Stack<>,并实现了泛型方法来对元素进行入栈出栈操作:
#include <iostream>
#include <vector>
#include <cstdlib>
#include <string>
#include <stdexcept>
using namespace std;
template <class T>
class Stack {
private:
vector<T> elems; // 元素
public:
void push(T const&); // 入栈
void pop(); // 出栈
T top() const; // 返回栈顶元素
bool empty() const{ // 如果为空则返回真。常函数,不可以修改成员变量,否则报错,是一种对数据的保护。
return elems.empty();
}
};
template <class T>
void Stack<T>::push (T const& elem)
{
// 追加传入元素的副本
elems.push_back(elem);
}
template <class T>
void Stack<T>::pop ()
{
if (elems.empty()) {
throw out_of_range("Stack<>::pop(): empty stack");
}
// 删除最后一个元素
elems.pop_back();
}
template <class T>
T Stack<T>::top () const
{
if (elems.empty()) {
throw out_of_range("Stack<>::top(): empty stack");
}
// 返回最后一个元素的副本
return elems.back();
}
int main()
{
try {
Stack<int> intStack; // int 类型的栈
Stack<string> stringStack; // string 类型的栈
// 操作 int 类型的栈
intStack.push(7);
cout << intStack.top() <<endl;
// 操作 string 类型的栈
stringStack.push("hello");
cout << stringStack.top() << std::endl;
stringStack.pop();
stringStack.pop();
}
catch (exception const& ex) {
cerr << "Exception: " << ex.what() <<endl;
return -1;
}
}
7
hello
Exception: Stack<>::pop(): empty stack
下一节复习
STL Containers容器
<array>数组
<bitset>位集合
<deque>双端队列
<forward_list>前向链表
<list>链表
<map>映射
<queue>队列
<set>集合
<unordered_map>无序映射
<unordered_set>无序集合
<vector>向量