01.vector的erase( )的返回值
返回的是一个迭代器,指向被删除元素的下一个位置。(迭代器指针的位置没变,其实是因为被删元素之后的元素向前移了)
如果删除元素之后没有元素了,直接返回尾迭代器
【example 1 start】指定一个元素,把vector中的这个元素全部删除
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 #include <iostream> #include <vector> #include <algorithm> using namespace std;void deleteElement (vector<int >&vc,int element) { auto it = vc.begin (); while (it!=vc.end ()){ if (*it==element){ it = vc.erase (it); continue ; } it++; } } int main (int argc,char * argv) { vector<int >vc{1 ,1 ,2 ,3 ,4 ,1 ,2 ,1 ,5 ,6 ,7 ,8 ,9 ,10 }; cout<<"Original elements------>" ; for_each(vc.begin (),vc.end (),[&](const int &ele){ cout<<ele<<" " ; }); cout<<endl; deleteElement (vc,1 ); cout<<"After delete element 1------->" ; for (auto & x:vc){ cout<<x<<" " ; } return 0 ; }
Running this code:
【example 1 end】
02.static关键字
用static修饰的东西就是一个全局变量,但是会有作用域限制(“私有的全局变量”)。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 void function () { static int x; int static y; } class Dog { private : int x = 100 ; int y; static int z; static const int a = 100 ; public : static int name; } int Dog::z = 100 ;
从文件的角度来看,用static修饰的东西只能在本文件内使用
1 2 3 4 5 6 static void show () ;
static应用:单例模式
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 class CSingleton {private : CSingleton (){} static CSingleton* m_pInstance; public : ~CSingleton () { if (m_pInstance != nullptr ) { delete m_pInstance; } } static CSingleton* getInstance () { if (m_pInstance == nullptr ) { m_pInstance = new CSingleton (); } return m_pInstance; } }; CSingleton* CSingleton::m_pInstance = nullptr ;
03.a对b真正的余数
04.C++构造函数初始化列表中不能使用this指针
this指针属于对象,初始化列表在构造函数之前执行,在对象还没有构造完成前,使用this指针,编译器无法识别。
构造函数中的内容,属于assignment,并不是初始化。
在初始化构造列表中,编译器可以区分和成员变量同名的函数参数
05.C++中输出一个对象
友元+重载<<
在重载输入输出运算符的时候,只能采用全局方式的方式(因为我们不能在ostream和istream类中编写成员函数),这才是友元函数的真正应用场景。对于输出运算符,主要负责打印输出对象的内容而非控制格式,不应该打印换行符;对于输入运算符,必须处理可能失败的情况(通常处理失败为默认的构造函数的形式)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 #include <iostream> #include <string> using namespace std;class Student { string name; int age; public : Student (){} Student (string name,int age):name (name),age (age){} friend ostream& operator <<(ostream&out,const Student&stu) { out << "name=" << stu.name << " age=" << stu.age; return out; } friend istream& operator >>(istream&in, Student&stu) { in >> stu.name >> stu.age; if (!in) { stu = Student (); } return in; } }; int main () { Student stu; cout << "请输入学生姓名和年龄:" << endl; cin >> stu; cout << stu; return 0 ; }
06.priority_queue的优先级设置
greater即按升序排列: 最小的----------------------------------------------------------------最大的
less即按降序排列: 最大的----------------------------------------------------------------最小的
但是要求类中要重载operator<和operator>,必须并且按照正常的逻辑处理。
1 2 priority_queue<类名,vector<类名>,greater<类名>> q; 队列中放的是什么类型 底层比较承载容器 仿函数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 #include <iostream> #include <string> #include <stack> #include <queue> #include <algorithm> using namespace std;class Fruit { string name; int price; public : Fruit (){} Fruit (string name,int price):name (name),price (price){} friend istream& operator >>(istream&in,Fruit&fruit) { in >> fruit.name >> fruit.price; if (!in) { fruit = Fruit (); } return in; } friend ostream& operator <<(ostream&out, const Fruit&fruit) { out << fruit.name << " " << fruit.price; return out; } bool operator <(const Fruit&ft) const { return this ->price < ft.price; } bool operator >(const Fruit&ft) const { return this ->price > ft.price; } }; int main () { Fruit apple; Fruit pear; Fruit strawberry; cin >> apple; cin >> pear; cin >> strawberry; priority_queue<Fruit, vector<Fruit>, greater<Fruit>> q1; priority_queue<Fruit, vector<Fruit>, less<Fruit>> q2; q1.push (apple); q1.push (pear); q1.push (strawberry); q2.push (apple); q2.push (pear); q2.push (strawberry); cout << q1.top () << endl; cout << q2.top () << endl; return 0 ; }
07.map插入一个pair
1 2 3 4 map<string, int >ma; ma.insert (map<string, int >::value_type ("java" , 20 )); ma.insert (make_pair ("C++" , 80 )); ma.insert (pair<string,int >("Python" , 10 ));
08.字符编码
1.将所有的字符映射成一个数字,这个数字是唯一的
2.这个数字在计算机中如何存储没有规定
Unicode只是一个字符集,它只规定了符号的二进制代码,却没有规定这个二进制代码在计算机中如何存储。
cmd命令窗口中,GBK代码页936,Unicode代码页65001。
09.C++单例模式
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 class Object {public : static Object* getInstance () ; private : class GarbageCollector ; static Object *m_obj; static GarbageCollector gc; class GarbageCollector { public : ~GarbageCollector () { if (Object::m_obj) { delete Object::m_obj; Object::m_obj = nullptr ; } } }; private : Object () {}; }; Object* Object::m_obj = nullptr ; Object::GarbageCollector Object::gc; Object* Object::getInstance () { if (m_obj == nullptr ) { m_obj = new Object (); } return m_obj; }
10.拷贝构造函数和operator= 的区别
1 2 3 4 5 6 7 8 9 10 11 12 class String { public : String (const char *cstr = 0 ); String (const String& str); String& operator =(const String&str); ~String (); char * get_c_str () const { return m_data; } private : char * m_data; };
11.常引用指向不同的数据时,会产生临时变量
常引用指向不同的数据时,会产生临时变量,即引用指向的并不是初始化的那个变量
1 2 3 4 int age = 20 ;const long &refAge = age;age = 30 ; std::cout<<refAge<<std::endl;
12.C++函数包装器
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 #include <functional> template <typename T,typename F>T run (T v, F f) { return f (v); } template <typename T,typename F>T run (T v1, T v2, F f) { return f (v1,v2); } std::function<函数返回值(函数参数)>对象名字 = 函数地址 std::function<double (double )> func1 = [](double v){return v*2 ;}; func1 (10.5 );run (10.5 ,func1);std::function<int (int ,int )> func2 = [](int v1,int v2){return v1+v2;}; func2 (10 ,20 );run (10 ,20 ,func2);
13.C++前置声明解决模板二次编译问题
类的前置声明
友元模板函数的前置声明
友元模板函数声明需要增加泛型的支持
声明和定义分别在不同的文件(模板函数、模板友元)或者尽量将模板函数和模板友元放在一个文件下。
将类的声明与函数的声明写在.h文件中
类的实现及函数的实现写在.hpp文件中
调用者包含.hpp文件
Complex.h文件,
存放类的声明和函数的声明
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 #include <iostream> using namespace std;template <typename T>class Complex ;template <typename T>ostream& operator <<(ostream &out, Complex<T> &c); template <typename T>class Complex { friend ostream& operator << (ostream &out, Complex<T> &c); public : Complex (T a, T b); Complex<T> operator +(Complex<T> &c); Complex<T> myAdd (Complex<T> &c1, Complex<T> &c2) ; private : T a; T b; };
Complex.hpp文件
存放模板函数的实现
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 #include "Complex.h" template <typename T>ostream& operator <<(ostream &out, Complex<T> &c) { out<<c.a << " + " << c.b << "i" ; return out; } template <typename T>Complex<T>::Complex (T a, T b) { this ->a = a; this ->b = b; } template <typename T>Complex<T> Complex<T>::operator +(Complex<T> &c) { Complex temp (this ->a + c.a, this ->b + c.b) ; return temp; } template <typename T>Complex<T> Complex<T>::myAdd (Complex<T> &c1, Complex<T> &c2) { Complex temp (c1.a + c2.a, c1.b + c2.b) ; return temp; }
14.std::ifstream::rdbuf
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 #include <iostream> #include <fstream> int main () { std::ifstream ifs ("test.txt" , std::ifstream::binary) ; std::filebuf* pbuf = ifs.rdbuf (); std::size_t size = pbuf->pubseekoff (0 ,ifs.end,ifs.in); pbuf->pubseekpos (0 ,ifs.in); char * buffer=new char [size]; pbuf->sgetn (buffer,size); ifs.close (); std::cout.write (buffer,size); delete [] buffer; return 0 ; }
15.rdbuf()简单实现文件拷贝
1 2 3 4 5 6 7 8 9 10 11 12 13 #include <fstream> #include <sstream> std::ifstream in ("./source.txt" ,std::ios::binary) ;std::ifstream out ("./copy.txt" ,std::ios::binary) ;out<<in.rdbuf (); 简要的理解:rdbuf () 返回“一个水流”,需要把它接(<<)到一个流对象上. 譬如stringstream.
16.C++对二进制文件的读写
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 #include <iostream> #include <fstream> #include <sstream> #include <vector> #include <string> #include <ctime> int main () { std::cout<<"Program starting......" <<std::endl; std::ifstream in; std::ofstream out; in.open ("./metadata.txt" ,std::ios::binary); out.open ("./cop.txt" ,std::ios::binary); clock_t start,end; start = clock (); out<<in.rdbuf (); end = clock (); std::cout<<"first:" <<(double )(end-start)/CLOCKS_PER_SEC<<"s" <<std::endl; in.close (); out.close (); in.open ("./metadata.txt" ,std::ios::binary); out.open ("./cop2.txt" ,std::ios::binary); const int buffer_size = 1024 *8 ; char * buffer = new char [buffer_size]; int n; start = clock (); while (in.peek ()!=EOF){ in.read (buffer,buffer_size); n = in.gcount (); out.write (buffer,n); } end = clock (); std::cout<<"second:" <<(double )(end-start)/CLOCKS_PER_SEC<<"s" <<std::endl; in.close (); out.close (); delete [] buffer; std::cout<<"\nProgram finished!" <<std::endl; return 0 ; } 注意:读取大文件时,方式2 要更快
17.随机文件访问
18.STL中为什么将top()和pop()这两个函数分开?
pop()函数返回void
top()函数返回栈顶元素的引用
One might wonder why pop()
returns void
, instead of value_type
. That is, why must one use top()
and pop()
to examine and remove the top element, instead of combining the two in a single member function? In fact, there is a good reason for this design. If pop()
returned the top element, it would have to return by value rather than by reference: return by reference would create a dangling pointer. Return by value, however, is inefficient: it involves at least one redundant copy constructor call. Since it is impossible for pop()
to return a value in such a way as to be both efficient and correct, it is more sensible for it to return no value at all and to require clients to use top()
to inspect the value at the top of the stack.
19.C++: warning: C4930: prototyped function not called (was a variable definition intended?)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 #include <iostream> using std::cout;using std::endl;class Computer {public : Computer () { cout << "Computer()" << endl; } ~Computer () { cout << "~Computer()" << endl; } }; class PC : public Computer {public : PC () { cout << "PC()" << endl; } ~PC () { cout << "~PC()" << endl; } }; class Desktop : public PC {public : Desktop () { cout << "Desktop()" << endl; } ~Desktop () { cout << "~Desktop()" << endl; } }; class Laptop : public PC {public : Laptop () { cout << "Laptop()" << endl; } ~Laptop () { cout << "~Laptop()" << endl; } }; int main () { PC d () ; PC l () ; std::cin.get (); return 0 ; }
上述代码中:
编译器无法分辨你当前的代码是在声明一个函数原型,还是在调用一个函数。所以上述代码不会打印任何东西!
再看如下例题:
现有以下代码,则编译时会报错的是( )
A. 语句1
B. 语句2
C. 语句3
D. 语句4
1 2 3 4 5 6 7 8 9 10 11 12 13 14 struct Test { Test (int ) {} Test (); void fun () {} }; int main () { Test a (1 ) ; a.fun (); Test b () ; b.fun (); return 0 ; }
答案: D Test b()这个语法相当于声明了一个函数,函数名为b,返回值为Test,传入的参数为空。但实际上,代码作者希望声明一个类型为Test,变量为b的变量,应该写成Test b ,但程序这个错误在编译时是检测不出来的,出错的是语句4 b.fun()
20. C++中构造函数的继承
using 父类名字::父类名字