函数模板:
A. 自动类型推导, 必须有参数类型符合才可以推导
template<typename T>
void swap(T &a, T &b) {
...
}
int main() {
char a = 10;
int b = 20;
swap(a, b);
return(0);
}
B. 调用时显式指定类型
swap<int>(...);
普通函数与模板函数的区别
1. 普通函数可以进行隐式类型转换而模板函数没有隐式类型转换
2. 模板函数与普通函数发生了重载,优先调用普通函数。如果就想调用模板函数则加上空参数列表, 比如: func<>(...)
3. 函数模板也可以发生重载
4. 如果模板函数更优,则选择模板(比如普通函数会发生隐式类型转换而模板函数不需要)
如果函数模板遇到不匹配的类型如何? 比如:
template<typename T>
bool Compare(T &t1, T &t2) {
return (t1 == t2 ? true : false);
}
如果传入了自定义类型class Person会出现错误, 可以通过具体化这种类型解决:
template<> bool Compare<Person>(Person &a, Person &b) {
if (a.m_iAge == b.m_iAge && a.m_strName == b.m_strName)
return(true);
else
return(false);
}
类模板:
A. 不支持自动类型推导!!! 特别是构造对象的时候, 必须显示指定类型, 比如: Person<string, int> p1("Joe", 100);
B. 类模板支持默认参数类型, 比如定义时: template <class NameType, class AgeType = int>
C. 类的成员函数一开始并不会创建,成员属性会。只有运行时调用了某个成员函数时才会创建出来从而确定了类模板的类型
类模板与函数配合使用(类模板实例传入函数)
1. 函数的形参列表可以指定类模板的类型
例如 void print(Person<string, int> &p);
2. 将函数写为函数模板,并配合类模板的参数传入形参(类模板实例)
例如 template<typename T1, typename T2> void print(Person<T1, T2> &p);
3. 将函数写为函数模板,但把类模板实例作为一个整体参数传入
例如template<typename T> void print(T &refClass);
类模板继承
A. 基类是模板类, 子类是普通类并继承基类, 则继承时要说明基类参数类型
template<class T>
class Base {
public:
T m_A;
};
class Child : public Base<int> {
};
B. 基类是模板类, 子类也是模板类并继承基类, 则继承时要传入基类参数类型(可以是普通类型也可以是子类中模板指定类型)
template<class T>
class Base {
public:
T m_A;
};
template<class T1, class T2>
class Child1 : public Base<T1> {
public:
Child1() {
cout << typeid(T1).name() << endl;
}
T2 m_B;
};
类模板类外实现成员函数:
template<class T>
class Base {
public:
T m_A;
};
template<class T1, class T2>
class Child1 : public Base<T1> {
public:
Child1() {
cout << typeid(T1).name() << endl;
}
T1 showPerson(T1 &p);
T2 m_B;
};
template<class T1, class T2>
T1 Child1::showPerson(T1 &p) {
return(p);
}
类模板分文件编写
由于模板类成员函数只会在调用时生成对应类型的函数,刚开始运行阶段不会生成
导致包含.h文件会失败
解决方案:
1. 包含*.cpp实现文件
2. 把头文件改成*.hpp并把实现搬到头文件中,使用时直接包含*.hpp
template <class T1, class T2>
class Person
{
public:
Person();
Person(T1 name, T2 age);
~Person();
void showPerson() {
cout << "姓名: " << m_Name << " 年龄: " << m_Age << endl;
}
private:
T1 m_Name;
T2 m_Age;
};
template<class T1, class T2>
Person<T1, T2>::Person()
{
}
template<class T1, class T2>
Person<T1, T2>::~Person()
{
}
template <class T1, class T2>
Person<T1, T2>::Person(T1 name, T2 age) : m_Name(name), m_Age(age)
{
}
A. 友元函数类内实现:
template <class T1, class T2>
class Person
{
friend void showPerson(Person<T1, T2> &p) {
cout << "姓名: " << p.m_Name << " 年龄: " << p.m_Age << endl;
}
public:
Person();
Person(T1 name, T2 age);
~Person();
private:
T1 m_Name;
T2 m_Age;
};
B. 友元函数类外实现:
template<class T1, class T2>
class Person;
template<class T1, class T2>
void showPerson(Person<T1, T2> &p);
template <class T1, class T2>
class Person
{
friend void showPerson<>(Person<T1, T2> &p);
private:
T1 m_Name;
T2 m_Age;
};
template <class T1, class T2>
void showPerson(Person<T1, T2> &p)
{
cout << "姓名: " << p.m_Name << " 年龄: " << p.m_Age << endl;
}
static_cast类型转换--->1. 父子关系 2. 基础数据类型 3.引用, 指针类型
dynamic_cast类型转换---> 1. 不能用于基础数据类型 2. 非常严格, 任何不安全的行为都会被阻止, 比如向下转换(发生多态则可以)
const_cast类型转换 --> 只能用于常指针与常引用
reinterpret_cast类型转换 ---> 非常不严格,基本都可以转,不推荐使用
异常处理:
int myDivide(int a, double b) {
if (b == 0.0)
throw(0.0);
if (b == 0)
throw(-1);
return(a / b);
}
int main() {
int a = 10;
float b = 0.0;
try {
myDivide(a, b);
}
catch (int) {
cout << "int出错了!" << endl;
}
catch (double) {
cout << "double出错了!" << endl;
}
catch (...) {
cout << "其他类型出错" << endl;
}
system("pause");
return(0);
}
如果不想处理可以使用throw继续向上抛出,但没有相应catch处理异常则会导致中断程序
自定义异常类:
class MyException {
public:
void PrintError() {
cout << "自定义异常" << endl;
}
};
int myDivide(int a, int b) {
if (b == 0)
throw MyException();
return(a / b);
}
int main() {
int a = 10;
float b = 0.0;
try {
myDivide(a, b);
}
catch (MyException e) {
e.PrintError();
}
system("pause");
return(0);
}
栈解旋: 从try开始到throw之前在栈上开辟的内存空间都会被释放
异常的生命周期:
// 调用拷贝构造和默认构造,导致两份开销
throw MyException();
catch (MyException e) {
cout << "捕获异常" << endl;
}
// 不调用拷贝构造只调用默认构造,只有一份开销
throw MyException();
catch (MyException &e) {
cout << "捕获异常" << endl;
}
// 异常类创建在堆区,需要自己释放异常类对象
throw (new MyException());
catch (MyException *e) {
cout << "捕获异常" << endl;
delete e;
}
异常的多态使用:
class BaseException {
public:
virtual void printError() {
}
};
class NullPointerException : public BaseException {
public:
virtual void printError() {
cout << "空指针异常" << endl;
}
};
class OutOfRangeException : public BaseException {
public:
virtual void printError() {
cout << "越界异常" << endl;
}
};
void doWork() {
throw(OutOfRangeException());
}
int main() {
try {
doWork();
}
catch (BaseException &e) {
e.printError();
}
system("pause");
return(0);
}
系统异常类:
#include <stdexcept>
class Person {
public:
Person(string name, int age) {
this->m_Name = name;
if (age < 0 || age > 200) {
throw(out_of_range("年龄越界了"));
}
if (name.size() > 10)
throw(length_error("名字太长了"));
}
string m_Name;
int m_Age;
};
void test() {
try {
Person p("张三", 300);
}
catch (out_of_range &e) {
cout << e.what();
}
catch (length_error &e) {
cout << e.what();
}
}
拓展系统异常类
class MyOutOfRangeException : public exception{
public:
MyOutOfRangeException(string error);
virtual ~MyOutOfRangeException();
virtual const char *what() const;
string m_ErrorInfo;
};
MyOutOfRangeException::MyOutOfRangeException(string error)
{
m_ErrorInfo = error;
}
MyOutOfRangeException::~MyOutOfRangeException()
{
}
const char * MyOutOfRangeException::what() const
{
return(this->m_ErrorInfo.c_str());
}
class Person {
public:
Person(string name, int age) {
this->m_Name = name;
if (age < 0 || age > 200) {
throw(MyOutOfRangeException("年龄越界了"));
}
}
string m_Name;
int m_Age;
};
void test() {
try {
Person p("张三", 300);
}
catch (MyOutOfRangeException &e) {
cout << e.what();
}
}
1. cin.get() 从标准输入中获取一个字符(包括换行符)
2. cin.get(buf, count) 从标准输入中获取字符串放到buf中(除了换行符, 其依旧在缓冲区中)
3. cin.getline(buf, count) 从标准输入中获取字符串放到buf中(会把换行符删去)
4. cin.ignore() 从标准输入中取出一个字符但是不获取
5. cin.peek() 从标准输入中查看字符并放回缓冲区,就像调用了cin.get()获取后把该字符放回
6. cin.putback(char) 调用cin.get()后调用cin.putback的效果类似于cin.peek()
下面代码如果输入了除了int类型意外的内容会导致无线循环else中内容
原因是如果缓冲区中出现了与接收类型不同的类型则会设置cin.fail()标志位导致一直出错
可以使用cin.clear()与cin.sync()来解除。cin.clear()清除标志位, cin.sync()清空缓冲区
int main() {
int num;
while (true) {
cin >> num;
if (num > 0 && num < 11) {
cout << "输入的数字为: " << num;
break;
}
else {
cout << "对不起,请重新输入" << endl;
cout << "标志位: " << cin.fail() << endl;
}
}
system("pause");
return(0);
}
流对象的成员函数
void test() {
char szBuf[1024] = "Hello, world";
cout.put('a').put('b'); // 字符输出
cout.write(szBuf, strlen(szBuf)); // 字符串输出
int num = 99;
cout.width(20); // 宽度设为20为(默认右对齐)
cout.fill('*'); // 把多出的宽度填充*字符
cout.setf(ios::left); // 设置为左对齐
cout.unsetf(ios::dec); // 卸载十进制
cout.setf(ios::hex); // 装载十六进制
cout << num;
}
#include <iomanip>
void test() {
int num = 99;
cout << setw(20) << setfill('&') << setiosflags(ios::showbase)
<< setiosflags(ios::left) << hex << num;
}
标准输入输出
void test() {
// ofstream ofs("D://test.txt", ios::out | ios::trunc);
ofstream ofs;
ofs.open("D:\\test.txt", ios::out);
if (!ofs.is_open())
cout << "打开失败!" << endl;
ofs << "姓名: 杨铭" << endl;
ofs << "年龄: 25" << endl;
ofs << "性别: 男" << endl;
ofs.close();
}
void test() {
ifstream ifs;
ifs.open("D:\\test.txt", ios::in);
if (!ifs.is_open())
cout << "打开失败" << endl;
char buf[1024];
// 按单词读取
/*
while (ifs >> buf) {
cout << buf << endl;
}
*/
// 按行读取
/*while (!ifs.eof()) {
ifs.getline(buf, 1024);
cout << buf << endl;
}*/
// 按单个字符读取
char ch;
while ((ch = ifs.get()) != EOF) {
cout << ch;
}
}
静态联编: 早绑定, 在编译阶段确定类型
动态联编: 晚绑定, 在运行阶段确定类型(多态)
重写: 父子类, 虚函数, 重新实现
1. 如果父类中有纯虚函数, 子类继承父类必须实现纯虚函数
2. 如果父类中有纯虚函数则父类无法实例化
虚析构是为了让析构函数也发生多态, 当父类指针指向子类对象时, 如果是普通虚构函数
则只会调用父类析构函数,如果是虚析构则会调用子类析构函数和父类析构函数
纯虚析构函数: 纯虚析构函数也属于纯虚函数(纯虚类),但与纯虚函数有点不用,
由于父类的析构函数也会被调用所以即使父类是纯虚析构函数也要进行实现,
而且是类内声明,类外实现。
=, [], (), ->操作符重载只能通过成员函数方式
<<和>>只能通过全局函数方式
&&和||不能进行重载因为无法实现短路原则
公共继承: 父类中所有权限在子类中保持原样
保护继承: 父类中除了private类型保持不可访问, 其他全部是protect方式访问权限
私有继承: 子类中继承父类的部分全是private访问权限
当继承出现时, 子类的确会继承父类的私有成员,但是被编译器隐藏起来, 所以无法访问
当继承出现时, 父子类的构造顺序是从父类到子类,而析构顺序是子类到父类,子类不会继承父类的构造和析构函数
当继承出现时, 父子类的同名成员的调用规则是就近原则。如果想要强制调用较远项可以用作用域运算符,子类并不会覆盖同名的父类
成员,两者都会出现在子类中
当继承出现时, 父类中的静态成员可以被子类继承(注意, 成员属性类内声明类外初始化, 成员函数无所谓)
多继承出现时,子类会继承多个父类的所有成员,包括同名(菱形继承使用虚继承解决)
STRING:
void stringTest1() {
// 构造
string str;
string str1("Hello, world");
string str2 = "Fuck world";
string str3(str1);
string str4(10, 'a');
// 拷贝构造
str1 = "Fuck";
str2 = 'b';
str3 = str4;
// assign方法
str3.assign("abcedf", 4); // 前4个字符
str3.assign(4, 'a');
str3.assign(str2);
str2.assign(str1, 0, 4);
}
void stringTest2() {
string s = "Hello, world!";
for (int i = 0; i < s.size(); ++i)
// [] 访问越界会挂掉, at访问越界会异常
//cout << s[i] << " ";
cout << s.at(i) << " ";
cout << endl;
}
void stringTest3() {
string s1 = "fd";
string s2 = "cvdf";
s1 += s2;
s1.append(s2);
int nPos = s1.find("vd");
s1.replace(1, 3, "fuck");
cout << s1 << endl;
}
void stringTest4() {
string s1 = "abc";
string s2 = "abc";
if (!s1.compare(s2))
cout << "s1 == s2" << endl;
else
cout << "s1 != s2" << endl;
string s3("Hello, world");
s1 = s3.substr(0, 4);
cout << s1 << endl;
string mail = "ki0pler@outlook.com";
int nPos = mail.find('@');
string k1 = mail.substr(0, nPos);
string k2 = mail.substr(nPos + 1, -1);
cout << k1 << endl;
cout << k2 << endl;
}
void stringTest5() {
string s1 = "hello";
s1.insert(1, "111");
cout << s1 << endl;
s1.erase(1, 3); // 位置, 数量
cout << s1 << endl;
const char *pStr = s1.c_str();
cout << pStr << endl;
string s2(pStr);
cout << s2 << endl;
}
VECTOR:
template<typename T>
void printVector(vector<T> &v) {
for (vector<T>::iterator it = v.begin(); it != v.end(); ++it)
cout << *it << " ";
cout << endl;
}
void vectorTest1() {
vector<int> v;
for (int i = 0; i < 10; ++i)
v.push_back(i + 1);
cout << v.capacity() << endl;
}
void vectorTest2() {
vector<int> v;
int arr[] = { 1, 3, 5, 7, 8 };
vector<int> v1(arr, arr + sizeof(arr) / sizeof(int));
vector<int> v2(v1.begin(), v1.end());
vector<int> v3(10, 100);
vector<int> v4;
v4.assign(v3.begin(), v3.end());
vector<int> v5;
v5.swap(v4);
printVector(v2);
printVector(v1);
printVector(v3);
printVector(v4);
printVector(v5);
if (v4.empty())
cout << "v4为空" << endl;
else
cout << "v4不为空" << endl;
v5.resize(20, -1); // -1为默认值
printVector(v5);
for (int i = 0; i < 10000; ++i)
v5.push_back(i + 100);
v5.resize(3); // 容量为超过10000 但大小为3
vector<int>(v5).swap(v5); // 利用V5初始化匿名对象(容量与大小合适)在与v5交换,结束后匿名对象被释放
v3.reserve(10000);
cout << v2.at(0) << " " << v2.front() << " " << v2.back() << endl;
v.insert(v.begin(), 2, 100);
v.pop_back();
v.erase(v.begin());
v.erase(v.begin(), v.end());
v3.clear();
}
void vectorTest3() {
int *p = NULL;
int num = 0;
vector<int> v;
for (int i = 0; i < 100; ++i)
v.push_back(i + 1);
for (vector<int>::reverse_iterator rit = v.rbegin(); rit != v.rend(); ++rit)
cout << *rit << " ";
cout << endl;
}
DEQUE:
template<typename T>
void printDeque(const deque<T> &d) {
for (deque<int>::const_iterator it = d.begin(); it != d.end(); ++it)
cout << *it << " ";
cout << endl;
return;
}
void dequeTest1() {
deque<int> d;
for (int i = 0; i < 4; ++i)
d.push_back(i * 100 + 1);
printDeque(d);
deque<int> d1(d.begin(), d.end() - 3);
d1.swap(d);
if (d1.empty())
cout << "d1为空" << endl;
else
cout << "d1不为空" << endl;
cout << d1.front() << " " << d1.back() << endl;
deque<int> d2;
d2.push_front(100);
d2.push_front(200);
d2.push_front(300);
d2.push_front(400);
d2.pop_back();
d2.pop_front();
printDeque(d2);
cout << d2.at(1) << endl;
d2.insert(d2.begin(), 100);
d2.insert(d2.begin(), d.begin(), d.end());
d2.clear();
}
STACK:
void testStack() {
stack<int> s;
for (int i = 0; i < 10; ++i)
s.push(i * 100 + 1);
while (s.size()) {
cout << "栈顶元素: " << s.top() << endl;
s.pop();
}
if (s.empty)
cout << "堆栈为空" << endl;
}
QUEUE:
void testQueue() {
queue<int> q;
q.push(10);
q.push(20);
q.push(30);
q.push(40);
while(!q.empty()) {
cout << "队头: " << q.front() << ", 队尾: " << q.back() << endl;
q.pop();
}
}
LIST:
template<typename T>
void printList(const list<T> &L) {
for (list<T>::const_iterator it = L.begin(); it != L.end(); ++it)
cout << *it << " ";
cout << endl;
}
bool myCompare(int v1, int v2) {
return(v1 > v2);
}
class Person {
public:
Person(string name, int age, int height) : m_Name(name), m_Age(age), m_Height(height) {
}
bool operator==(const Person &p1) {
return(this->m_Age == p1.m_Age &&
this->m_Name == p1.m_Name &&
this->m_Height == p1.m_Height);
}
string m_Name;
int m_Age;
int m_Height;
};
bool comparePerson(Person &p1, Person &p2) {
if (p1.m_Age == p2.m_Age)
return(p1.m_Height > p2.m_Height);
else
return (p1.m_Age > p2.m_Age);
}
void testList() {
list<int> L1(10, 20);
list<int> L2(L1.begin(), L1.end());
for (list<int>::reverse_iterator it = L2.rbegin(); it != L2.rend(); ++it)
cout << *it << " ";
cout << endl;
list<int> L3;
for (int i = 0; i < 10; ++i)
L3.push_back(i * 100);
printList(L3);
L3.pop_front();
L3.pop_back();
L3.insert(L3.begin(), 1000);
L3.insert(L3.begin(), 3, 5);
L3.push_back(10);
L3.remove(10);
printList(L3);
if (L3.empty())
cout << "L3为空" << endl;
else
cout << "L3不为空" << endl;
list<int> L4;
L4.assign(L3.begin(), L3.end());
printList(L4);
L4.reverse();
printList(L4);
L4.sort(myCompare);
printList(L4);
L3.resize(3);
printList(L3);
list<Person> L;
Person p1("Jack", 10, 175);
Person p2("Tom", 12, 185);
Person p3("Lucy", 13, 190);
Person p4("Nohn", 14, 200);
Person p5("Flu", 15, 164);
Person p6("Fla", 14, 166);
L.push_back(p1);
L.push_back(p2);
L.push_back(p3);
L.push_back(p4);
L.push_back(p5);
L.push_back(p6);
L.sort(comparePerson);
for (list<Person>::iterator it = L.begin(); it != L.end(); ++it)
cout << "姓名: " << it->m_Name << ", 年龄: " << it->m_Age << ", 身高: " << it->m_Height << endl;
cout << endl;
L.remove(p3);
for (list<Person>::iterator it = L.begin(); it != L.end(); ++it)
cout << "姓名: " << it->m_Name << ", 年龄: " << it->m_Age << ", 身高: " << it->m_Height << endl;
cout << endl;
}
SET:
template <typename T>
void printSet(const set<T> &s) {
for (set<T>::const_iterator it = s.begin(); it != s.end(); ++it)
cout << *it << " ";
cout << endl;
}
class MyCompare {
public:
bool operator()(int v1, int v2) {
return(v1 > v2);
}
};
class Person {
public:
Person(string name, int age) : m_Name(name), m_Age(age) {
}
string m_Name;
int m_Age;
};
class cmpPerson {
public:
bool operator()(const Person &p1, const Person &p2) {
return(p1.m_Age > p2.m_Age);
}
};
void testSet() {
set<int> s1;
s1.insert(5);
s1.insert(1);
s1.insert(7);
s1.insert(4);
s1.insert(12);
s1.insert(23);
s1.insert(12);
s1.insert(12);
printSet(s1);
if (s1.empty())
cout << "该集合是空的" << endl;
else
cout << "该集合不是空的" << endl;
s1.erase(5);
printSet(s1);
set<int> s2(s1);
s2.erase(s2.begin(), s2.end());
set<int>::iterator it = s1.find(12);
if (it != s1.end())
cout << "找到了: " << *it << endl;
else
cout << "没有找到!" << endl;
// 由于set是不能重复的,所以count要么是1要么是0
cout << "12的个数是: " << s1.count(12) << endl;
set<int>::iterator it1 = s1.lower_bound(4); // >= 4
if (it1 != s1.end())
cout << "找到了lower_bound, 值为: " << *it1 << endl;
set<int>::iterator it2 = s1.upper_bound(4); // > 4
if (it2 != s1.end())
cout << "找到了lower_bound, 值为: " << *it2 << endl;
pair<set<int>::iterator, set<int>::iterator> ret = s1.equal_range(3);
if (ret.first != s1.end())
cout << "找到equal_range的值" << *(ret.first) << endl;
else
cout << "未找到";
if (ret.second != s1.end())
cout << "找到equal_range的值" << *(ret.second) << endl;
else
cout << "找到了";
set<int> s3;
pair<set<int>::iterator, bool> ret3 = s3.insert(10);
if (ret3.second)
cout << "插入成功" << endl;
else
cout << "插入失败" << endl;
pair<set<int>::iterator, bool> ret1 = s3.insert(10);
if (ret1.second)
cout << "插入成功" << endl;
else
cout << "插入失败" << endl;
set<int, MyCompare> s4;
s4.insert(5);
s4.insert(1);
s4.insert(7);
s4.insert(4);
s4.insert(12);
for (set<int, MyCompare>::iterator it3 = s4.begin(); it3 != s4.end(); ++it3)
cout << *it3 << " ";
cout << endl;
set<Person, cmpPerson> s5;
s5.insert(Person("aaa", 1));
s5.insert(Person("bbb", 2));
s5.insert(Person("ccc", 3));
s5.insert(Person("ddd", 4));
s5.insert(Person("eee", 5));
for (set<Person, cmpPerson>::iterator it4 = s5.begin(); it4 != s5.end(); ++it4)
cout << "姓名: " << (*it4).m_Name << " 年龄: " << it4->m_Age << endl;
}
PAIR:
void testPair() {
pair<string, int> p(string("Tom"), 100);
cout << p.first << " " << p.second << endl;
pair<string, int> p2 = make_pair("Jerry", 200);
cout << p2.first << " " << p2.second << endl;
}
MAP:
class myCompare {
public:
bool operator()(int v1, int v2) {
return(v1 > v2);
}
};
void testMap() {
map<int, int> m;
m.insert(pair<int, int>(1, 10));
m.insert(make_pair(2, 20));
m.insert(map<int, int>::value_type(3, 30));
m[4] = 40;
for (map<int, int>::iterator it = m.begin(); it != m.end(); ++it)
cout << "key = " << it->first << ", value = " << it->second << endl;
if (m.empty())
cout << "map为空" << endl;
else
cout << "map不为空" << endl;
cout << "map的size: " << m.size() << endl;
m.erase(1); // base key
for (map<int, int>::iterator it = m.begin(); it != m.end(); ++it)
cout << "key = " << it->first << ", value = " << it->second << endl;
map<int, int>::iterator it1 = m.find(2);
if (it1 != m.end())
cout << it1->first << " " << it1->second << "找到了!" << endl;
else
cout << "没有找到!" << endl;
int num = m.count(3); // 0个或1个, 因为map不能重复
map<int, int>::iterator ret = m.lower_bound(2);
if (ret != m.end())
cout << "lower_bound: " << ret->first << " " << ret->second << endl;
else
cout << "没有找到" << endl;
map<int, int>::iterator ret1 = m.upper_bound(2);
if (ret1 != m.end())
cout << "lower_bound: " << ret1->first << " " << ret1->second << endl;
else
cout << "没有找到" << endl;
pair<map<int, int>::iterator, map<int, int>::iterator> ret2 = m.equal_range(2);
if (ret2.first != m.end())
cout << "lower_bound的key: " << ret2.first->first << ", value: " << ret2.first->second << endl;
if (ret2.second != m.end())
cout << "upper_bound的key: " << ret2.second->first << ", value: " << ret2.second->second << endl;
map<int, int, myCompare> m1;
m1.insert(pair<int, int>(1, 10));
m1.insert(make_pair(2, 20));
m1.insert(map<int, int>::value_type(3, 30));
m1[4] = 40;
for (map<int, int, myCompare>::iterator it = m1.begin(); it != m1.end(); ++it)
cout << "key = " << it->first << " value = " << it->second << endl;
}
一个练习用的案例:
enum {RESOURCE, RESEARCH, ART};
class employee {
public:
employee();
string m_Name;
int m_Age;
string m_Tel;
int m_Salary;
};
employee::employee()
{
}
void createWorker(vector<employee> &v) {
string nameSeed = "ABCDE";
for (int i = 0; i < 5; ++i) {
string name = "员工";
name += nameSeed[i];
int iSalary = rand() % 10000 + 10000;
employee e;
e.m_Name = name;
e.m_Salary = iSalary;
v.push_back(e);
}
}
void setGroup(vector<employee> &v, multimap<int, employee> &m) {
for (vector<employee>::iterator it = v.begin(); it != v.end(); ++it) {
int deprtmtId = rand() % 3;
m.insert(make_pair(deprtmtId, *it));
}
}
void showGroup(multimap<int, employee> &m) {
cout << "人力部门员工如下: " << endl;
multimap<int, employee>::iterator it = m.find(RESOURCE);
int index = 0;
int num = m.count(RESOURCE);
for (; it != m.end() && index < num; ++it, ++index)
cout << "姓名: " << it->second.m_Name << ", 工资: " << it->second.m_Salary << endl;
cout << "研发部门员工如下: " << endl;
it = m.find(RESEARCH);
index = 0;
num = m.count(RESEARCH);
for (; it != m.end() && index < num; ++it, ++index)
cout << "姓名: " << it->second.m_Name << ", 工资: " << it->second.m_Salary << endl;
cout << "美术部门员工如下: " << endl;
it = m.find(ART);
index = 0;
num = m.count(ART);
for (; it != m.end() && index < num; ++it, ++index)
cout << "姓名: " << it->second.m_Name << ", 工资: " << it->second.m_Salary << endl;
}
int main() {
vector<employee> v;
multimap<int, employee> m;
srand((unsigned)time(NULL));
createWorker(v);
setGroup(v, m);
showGroup(m);
system("pause");
return(0);
}
函数对象:
class MyPrint {
public:
void operator()(int num) {
cout << "num: " << num << endl;
}
};
void doPrint(MyPrint print, int num) {
print(num);
}
void testFuncObj() {
MyPrint myPrint;
myPrint(10);
MyPrint()(100);
doPrint(MyPrint(), 20);
}
谓词(在仿函数中重载()操作符时返回bool类型即为谓词):
class GreaterThan {
public:
bool operator()(int val) {
return(val > 400);
}
};
class myCmp {
public:
bool operator()(int v1, int v2) {
return(v1 > v2);
}
};
void testVerb() {
vector<int> v;
for (int i = 0; i < 10; ++i)
v.push_back(i * 100 + 1);
vector<int>::iterator it = find_if(v.begin(), v.end(), GreaterThan()); // 谓词放入要是一个函数对象
if (it != v.end())
cout << "找到大于400的数字为: " << *it << endl;
else
cout << "没有找到!" << endl;
sort(v.begin(), v.end(), myCmp());
for_each(v.begin(), v.end(), [](int val){cout << val << " ";});
}
内建函数对象:
void testInsideFunc() {
negate<int> n;
cout << n(10) << endl;
plus<int> p;
cout << p(10, 15) << endl;
vector<int> v;
for (int i = 0; i < 5; ++i)
v.push_back(i * 100 + 1);
sort(v.begin(), v.end(), greater<int>());
for_each(v.begin(), v.end(), [](int val){cout << val << " ";});
}
适配器:
class MyPrint : public binary_function<int, int, void> {
public:
void operator()(int v, int start) const {
cout << v + start << endl;
}
};
class GreaterThan5 : public unary_function<int, bool> {
public:
bool operator()(int v) const {
return(v > 5);
}
};
void myPrint(int v, int start) {
cout << v + start << endl;
}
class Person {
public:
Person(string name, int age) : m_Name(name), m_Age(age) {
}
void showPerson() {
cout << "姓名: " << m_Name << ", 年龄: " << m_Age << endl;
}
void plusAge() {
this->m_Age += 100;
}
string m_Name;
int m_Age;
};
void testAdaptor() {
vector<int> v;
for (int i = 0; i < 10; ++i)
v.push_back(i);
for_each(v.begin(), v.end(), bind2nd(MyPrint(), 10));
for_each(v.begin(), v.end(), bind1st(MyPrint(), 10));
// 二元一元适配器
vector<int>::iterator it = find_if(v.begin(), v.end(), not1(GreaterThan5()));
if (it != v.end())
cout << "找到大于5的数字为: " << *it << endl;
else
cout << "未找到" << endl;
vector<int>::iterator it1 = find_if(v.begin(), v.end(), not1(bind2nd(greater<int>(), 5)));
if (it != v.end())
cout << "找到大于5的数字为: " << *it << endl;
else
cout << "未找到" << endl;
// 函数指针适配器
for_each(v.begin(), v.end(), bind2nd(ptr_fun(myPrint), 100));
vector<Person> v1;
Person p1("a", 1);
Person p2("b", 2);
Person p3("v", 3);
Person p4("d", 4);
v1.push_back(p1);
v1.push_back(p2);
v1.push_back(p3);
v1.push_back(p4);
// 成员函数适配器
for_each(v1.begin(), v1.end(), mem_fun_ref(&Person::plusAge));
for_each(v1.begin(), v1.end(), mem_fun_ref(&Person::showPerson));
}
常用遍历算法:
class myPrint {
public:
void operator()(int v) {
cout << v << endl;
m_Count++;
}
int m_Count;
};
class myPrint1 : public binary_function<int, int, void>{
public:
void operator()(int v, int start) const {
cout << v + start << endl;
}
};
class Transform {
public:
int operator()(int val) {
return(val + 10);
}
};
class Transform1 {
public:
int operator()(int val1, int val2) {
return(val1 + val2);
}
};
void testTraverseAlg() {
vector<int> v;
for (int i = 0; i < 10; ++i)
v.push_back(i + 10);
myPrint prt = for_each(v.begin(), v.end(), myPrint());
cout << "打印数量: " << prt.m_Count << endl;
for_each(v.begin(), v.end(), bind2nd(myPrint1(), 10000));
vector<int> vTarget;
vTarget.resize(v.size());
transform(v.begin(), v.end(), vTarget.begin(), Transform());
for_each(vTarget.begin(), vTarget.end(), [](int val) {cout << val << " "; });
vector<int> vFinal;
vFinal.resize(v.size() + vTarget.size());
transform(v.begin(), v.end(), vTarget.begin(), vFinal.begin(), Transform1());
for_each(vFinal.begin(), vFinal.end(), [](int val) {cout << val << " "; });
}
常用查找算法:
class Person {
public:
Person(string name, int age) : m_Name(name), m_Age(age) {
}
bool operator==(const Person &p) {
if (m_Name == p.m_Name && m_Age == p.m_Age)
return(true);
else
return(false);
}
string m_Name;
int m_Age;
};
class MyCompare : public binary_function<Person *, Person *, bool>{
public:
bool operator()(Person *p1, Person *p2) const {
if (p1->m_Name == p2->m_Name && p1->m_Age == p2->m_Age)
return(true);
else
return(false);
}
};
class MyComare1 {
public:
bool operator()(Person *p1) {
if (p1->m_Name == "b" && p1->m_Age == 20)
return(true);
else
return(false);
}
};
class GreaterThan4 {
public:
bool operator()(int v) {
return(v >= 4);
}
};
void test() {
vector<int> v;
for (int i = 0; i < 10; ++i)
v.push_back(i);
vector<int>::iterator it = find(v.begin(), v.end(), 5);
if (it != v.end())
cout << "找到了数字: " << *it << endl;
else
cout << "没有找到数字" << endl;
vector<Person> v1;
Person p1("a", 1);
Person p2("b", 2);
Person p3("v", 3);
Person p4("d", 4);
v1.push_back(p1);
v1.push_back(p2);
v1.push_back(p3);
v1.push_back(p4);
vector<Person>::iterator it1 = find(v1.begin(), v1.end(), p2);
if (it1 != v1.end())
cout << "姓名: " << (*it1).m_Name << ", 年龄: " << (*it1).m_Age << endl;
else
cout << "没有找到!" << endl;
vector<Person *> v2;
Person *pk1 = new Person("a", 10);
Person *pk2 = new Person("b", 20);
Person *pk3 = new Person("c", 30);
Person *pk4 = new Person("d", 40);
Person *pk5 = new Person("e", 50);
v2.push_back(pk1);
v2.push_back(pk2);
v2.push_back(pk3);
v2.push_back(pk4);
v2.push_back(pk5);
Person *p = new Person("b", 20);
vector<Person *>::iterator pos = find_if(v2.begin(), v2.end(), bind2nd(MyCompare(), p));
if (pos != v2.end())
cout << "找到了数据姓名: " << (*pos)->m_Name << ", 年龄: " << (*pos)->m_Age << endl;
else
cout << "未找到" << endl;
vector<Person *>::iterator pos0 = find_if(v2.begin(), v2.end(), MyComare1());
if (pos0 != v2.end())
cout << "姓名: " << (*pos0)->m_Name << "年龄: " << (*pos0)->m_Age << endl;
else
cout << "没有找到!" << endl;
vector<int> v3;
for (int i = 0; i < 10; ++i)
v3.push_back(i + 10);
v3.push_back(19);
vector<int>::iterator pos5 = adjacent_find(v3.begin(), v3.end());
if (pos5 != v3.end())
cout << *pos5 << endl;
else
cout << "没有找到元素" << endl;
bool ret = binary_search(v3.begin(), v3.end(), 19);
if (ret)
cout << "找到了" << endl;
else
cout << "没有找到" << endl;
int iNum = count_if(v.begin(), v.end(), GreaterThan4());
cout << "大于4的个数为: " << iNum << endl;
}
常用排序算法:
void testSortAlg() {
vector<int> v1, v2;
for (int i = 0; i < 10; ++i) {
v1.push_back(i);
v2.push_back(i + 1);
}
vector<int> vTarget;
vTarget.resize(v1.size() + v2.size());
merge(v1.begin(), v1.end(), v2.begin(), v2.end(), vTarget.begin());
for_each(vTarget.begin(), vTarget.end(), [](int v) {cout << v << " "; });
cout << endl;
vector<int> v3;
for (int i = 10; i > 0; --i)
v3.push_back(i * 10);
sort(v1.begin(), v1.end(), greater<int>());
random_shuffle(v1.begin(), v1.end());
for_each(v1.begin(), v1.end(), [](int v) {cout << v << " "; });
cout << endl;
reverse(v1.begin(), v1.end());
for_each(v1.begin(), v1.end(), [](int v) {cout << v << " "; });
}
常用复制和替换算法
class MyCompare {
public:
bool operator()(int val) {
return(val > 3);
}
};
void testCopyAndReplace() {
vector<int> v1;
for (int i = 0; i < 10; ++i)
v1.push_back(i);
vector<int> vTarget;
vTarget.resize(v1.size());
copy(v1.begin(), v1.end(), vTarget.begin());
for_each(vTarget.begin(), vTarget.end(), [](int v) {cout << v << " "; });
cout << endl;
copy(vTarget.begin(), vTarget.end(), ostream_iterator<int>(cout, " "));
replace(vTarget.begin(), vTarget.end(), 3, 10);
cout << endl;
copy(vTarget.begin(), vTarget.end(), ostream_iterator<int>(cout, " "));
replace_if(v1.begin(), v1.end(), MyCompare(), 3);
cout << endl;
for_each(v1.begin(), v1.end(), [](int val) {cout << val << " "; });
cout << endl;
vector<int> v2, v3;
for (int i = 0; i < 10; ++i)
v2.push_back(i + 1);
v3.push_back(10);
v3.push_back(20);
swap(v2, v3);
for_each(v2.begin(), v2.end(), [](int val) {cout << val << " "; });
cout << endl;
for_each(v3.begin(), v3.end(), [](int val) {cout << val << " "; });
}
常用算数算法(numeric):
void CalcGen() {
vector<int> v1, v2;
for (int i = 0; i < 10; ++i)
v1.push_back(i);
int sum = accumulate(v1.begin(), v1.end(), 0);
cout << "总和为:" << sum << endl;
v2.resize(10);
fill(v2.begin(), v2.end(), 100);
for_each(v2.begin(), v2.end(), [](int val) {cout << val << " "; });
}
案例:
class Speaker {
public:
Speaker() {
memset(m_iScore, 0, sizeof(int) * 3);
m_strName = "选手";
}
public:
string m_strName;
int m_iScore[3];
};
void createSpeakers(map<int, Speaker> &m, vector<int> &v) {
string strHash = "ABCDEFGHIJKLMNOPQRSTUVWX";
for (int i = 0; i < strHash.size(); ++i) {
Speaker CSpk;
deque<int> dqScore;
string strName("选手");
strName += strHash[i];
CSpk.m_strName = strName;
memset(&CSpk.m_iScore[0], 0, sizeof(int) * 3);
v.push_back(i + 100);
m.insert(make_pair(i + 100, CSpk));
}
}
void GameStart(int index, vector<int> &v1, map<int, Speaker> &m, vector<int> &v2) {
deque<int> dqScore;
for (map<int, Speaker>::iterator it = m.begin(); it != m.end(); ++it) {
for (int i = 0; i < 10; ++i)
dqScore.push_back(rand() % 61 + 40);
dqScore.pop_back();
dqScore.pop_front();
sort(dqScore.begin(), dqScore.end());
int sum = accumulate(dqScore.begin(), dqScore.end(), 0);
int avg = sum / dqScore.size();
(it->second).m_iScore[index - 1] = avg;
dqScore.clear();
}
int iGrp = 1;
multimap<int, int, greater<int> > tmpGroup;
for (int i = 0; i < v1.size(); ++i, ++iGrp) {
tmpGroup.insert(make_pair(m[v1[i]].m_iScore[index - 1], v1[i]));
if (iGrp % 6 == 0) {
multimap<int, int, greater<int> >::iterator it = tmpGroup.begin();
for (int j = 0; j < 3; ++j, ++it)
v2.push_back(it->second);
tmpGroup.clear();
}
}
}
void showResult(map<int, Speaker> &m, vector<int> &v, int index) {
cout << "第" << index << "轮晋级选手:" << endl;
for (vector<int>::iterator it = v.begin(); it != v.end(); ++it)
cout << "编号: " << *it << ", 姓名: " << m[*it].m_strName << ", 成绩: " << m[*it].m_iScore[index - 1] << endl;
putchar('\n');
}
void checkScore(int iId, map<int, Speaker> &m, int index) {
cout << "编号: " << iId << "成绩: " << m[iId].m_iScore[index - 1] << endl;
}
int main() {
vector<int> vecRnd1, vecRnd2, vecRnd3, vecRnd4;
map<int, Speaker> m;
createSpeakers(m, vecRnd1);
random_shuffle(vecRnd1.begin(), vecRnd1.end());
GameStart(1, vecRnd1, m, vecRnd2);
for (map<int, Speaker>::iterator it = m.begin(); it != m.end(); ++it) {
cout << "编号: " << it->first << ", 姓名: " << (it->second).m_strName << endl;
cout << "成绩: " << it->second.m_iScore[0] << endl << endl;
}
showResult(m, vecRnd2, 1);
random_shuffle(vecRnd2.begin(), vecRnd2.end());
GameStart(2, vecRnd2, m, vecRnd3);
showResult(m, vecRnd3, 2);
random_shuffle(vecRnd3.begin(), vecRnd3.end());
GameStart(3, vecRnd3, m, vecRnd4);
showResult(m, vecRnd4, 3);
system("pause");
return(0);
}
default用法: 由于定义了含参的构造函数后, 会取消默认构造函数,使用default则可以显式要求生成合成的构造或者拷贝控制成员,并且我们也只能对这些成员使用
delete用法: 用于通知编译器不定义某些成员,任何函数都可以被定义为delete, 主要用途是禁止拷贝控制成员。注意!析构函数无法被delete
动态类型与静态类型的概念:
1. 静态类型是编译时总是已知的,它是变量声明时的类型或表达式生成的类型
2. 动态类型是只有变量或表达式在内存中的对象的类型,只有到运行时才可知
3. 如果表达式既不是指针也不是引用则动态类型与静态类型永远一致
4. 基类的指针或引用的静态类型可能与其运行时的动态类型不一致
虚函数:
1. 由于基类指针或引用绑定的对象可能不同,所以在其调用一个虚函数时会执行动态绑定(只有通过指针或引用调用虚函数才会发生)。所以我们直到运行时才能知道其调用了哪一个版本的虚函数,因此所有派生类所继承的虚函数必须被重写。
2. 一旦类中某个函数被声明为虚函数则该类的所有派生类中该函数都为虚函数, 且派生类该函数的形参必须与基类一致,返回值同样也是,除非一种特例那就是基类虚函数返回类型本身的指针或引用,则派生类可以返回其自身类的指针或引用: 基类D的虚函数返回D *,派生类B可以返回B *而非D *。要求D与B的转换是可以具有可访问性。
1. 派生类对于public继承下来的基类的protected成员。无论是派生类的友元函数还是成员函数都只能访问派生类继承下来的那部分,而不能直接访问基类的protected部分
2. 只有公有继承方式才能使用向上转换即把基类指针或引用指向子类
3. 无论是什么继承方式, 派生类的友元或者成员函数都可以使用基类指针或引用执行向上转换
4. 假设A是爷爷类, B是爸爸类, C是儿子类。那么只有当爸爸类公有或保护继承爷爷类时,儿子类才能执行B到A的向上转换
override与final:
final放在函数末尾或者类的末尾代表不可以在被继承,比如:
class Base : public A final { ... };
class Base final {...};
override放在派生类的虚函数后面明确表示其为虚函数继承实现, 放在普通成员函数后面会报错,比如:
class Base {
virtual void print() {...};
};
class Derived : public Base {
void print() override {...};
};