• 写sort的时候可以用lambda表达式

    1
    sort(vi.begin(),vi.end(),[](const int elem1, const int elem2)->bool{return elem1<elem2;}); 
  • stl中的set有set_intersection,set_union,set_difference的功能,使用方法如

    1
    set_difference(a.begin(),a.end(),b.begin(),b.end(),inserter(c,c.begin()));
  • unique_copy是unique相似用法

    1
    unique_copy(ss.begin(),ss.end(),back_inserter(s));
  • extern int i代表要到别的文件中找i

  • vector<int>::const_iterator it1;//这玩意是不能改指向的数据
    const vector<int>::iterator it2;//这玩意是自己不能改,没啥用
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15

    * const的含义是不能修改,可能是不能被修改的变量;constexpr的含义是真正的常量(比如固定的数字),可以直接在编译期处理出来

    * 加::可以在局部调用全局变量,即使局部有同名变量

    * const int *p或者int const *p表示p指向的位置是个常量,但p不是;int *const p即可。若需要两者皆为常量,则int const *const p

    * nullptr代表空指针,但c中是NULL或0

    * 文件输入输出流fstream包含ifstream和ofstream,定义时

    ```c++
    ifstream fin{"a.txt"};//或者下面这样
    ifstream fin;fin.open("a.txt");//注意程序结束前要close
    fin.close();
    然后fin就可以当作一般的cin差不多用法了。 同时,这里定义的fin和cin都属于istream,其它也属于istream的还有stringstream,用法如下
    1
    2
    3
    4
    string s;
    stringstream strin(s);
    int n;
    strin>>n;
  • cin>>当中右移符号的返回值为左端的istream&对象,因此在cin>>x>>y中,cin>>x执行完返回一个cin,继续读cin>>y。判断语句中cin会被强转为bool型。当cin.eof()为true的时候条件判断中的cin是false

    1
    2
    3
    while (cin>>n) {/*what you want to do here*/}
    while (getline(cin,s)) {/*...*/}//返回值实际上也是个istream&,和上面这句的返回值类型相同
    while (!cin.eof()) {cin>>n;/*...*/}

    //这里不加点东西就会渲染失败

  • void f(char);
    void g(char &);
    void h(const char&);
    char c='A';int d=97;
    f('a');//right
    f(49);//right
    f(c);//right
    f(d);//right
    g('a');//wrong you can't refer a constant
    g(49);//wrong
    g(c);//right
    g(d);//wrong you can't refer a different variable type
    h('a');//right  the compiler would introduce a temporary variable
    h(49);//right the compiler would introduce a temporary variable
    h(c);//right
    h(d);//right the compiler would introduce a temporary variable
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    //这里不加点东西就会渲染失败

    * ```c++
    namespace My
    {
    int a;
    void f(){a++};
    }
    namespace AA
    {
    using namespace My;//直接把两个杂糅起来
    }
    namespace AA
    {
    int b;//这样算作添加
    }
    int main()
    {
    using namespace My;//1 introduce all,更接近于全局和局部的关系
    using My::f;//2 introduce My::f
    using My::a;//3 introduce My::a,只引入了一个局部标识符,和下面a同级
    int a;//4 与上面这行会矛盾,但与1不矛盾
    cout<<a<<My::a<<endl;
    }
  • for static global names, use unnamed namespace to avoid their use in other source files.

    如果是全局变量,就会在所有文件内生效,就乱套啦

    1
    2
    3
    4
    5
    6
    7
    8
    namespace//effective in the whole source file 
    {
    int a;
    }
    void f()
    {
    a=1;
    }
  • ADL技术,又称koenig查找,会根据参数所在的命名空间找调用的函数

  • namespace s=std;//重命名
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12

    * ODR技术 单一命名规则:不在同一个翻译空间内的两个一模一样的东西(名称和内部变量名等一切会被编译的东西),会被认为是同一个东西,不会报错。(但是它有啥用?)

    * C++默认会把函数名改成包含参数和返回值信息的样子,来内部区分

    * ```c++
    int &use_count()//alternative to use global variables
    {
    static int uc=initval;
    return uc
    }
    void f(){use_count()++;}
  • try catch throw

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    int f(int a,int b)
    {
    if (b==0) throw div0(1);
    if (a==0) throw div0(2);
    if (b==0x3f3f3f3f) throw aaa;//if no catch matches it, the program will terminate
    return a/b+b/a;
    }
    int main()
    {
    int n=1,m=0;
    try:
    {
    f(n,m);
    }
    catch(div0 x)
    {
    cout<<"div0"<<x<<endl;
    }
    //catch(...) to catch all other types
    }
  • 默认的class赋值是bitwise,但是如果里面有指针可能会出锅(从其中一个把它delete之后另一边就gg)

  • class A{
        int d;
        public:
            int getd() const;
            int getd(); //构成重载,会自动适配
        //重载就是同一个变量名不同函数
    }
    int A::getd() const{return d;}
    int A::getd(){return d++;}
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    //这里不加点东西就会渲染失败

    * ```c++
    class A
    {
    private:
    int x,y;
    public:
    A& operator+(const &A);//A后面的&表示返回一个引用,可以修改。否则返回的是const的局部变量
    //返回值记得设return *this;
    }
    //这里不加点东西就会渲染失败
  • class A
    {
        void operator==(const &A)=delete//禁止使用默认的==运算符
        void operator&(const &A)=delete//禁止使用默认的取地址运算符
    }
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    //这里不加点东西就会渲染失败

    * ```c++
    class complex
    {
    public:
    complex& operator+(const int &b);
    };
    complex a;
    int main(){2+a//wrong 只定义了a+2,没定义2+a
    //但是可以在class里面写个complex(const int &b) {x=b;}然后它就会自动转类型了
  • 由于ADL,namespace当中会自动寻找操作数相同的重定义运算符来用。重载前后操作数相同,不能变化结合性

  • operator.和operator->的左边的东西不会被隐式转换

  • 字面量操作符literal,可以实现1+2.0i这样的表示,方法就是

    1
    complex operator""_i(long double x){return {0,x};}//必须放在class外

    其中long double是因为double不合法…这些是合法类型

    1
    2
    3
    4
    5
    6
    7
    char const*
    unsigned long long
    long double
    char const*, std::size_t
    wchar_t const*, std::size_t
    char16_t const*, std::size_t
    char32_t const*, std::size_t

    老师ppt给的例子的字面量操作符没有下划线,但是貌似用户自定义的建议以下划线开头,因为以后的c++版本可能会用到不带下划线的。只会报warning

  • 假设需要把当前class转化为已有类型T,那么在class里面写operator T(const T &x)const{return xxxx;}

  • 在某些式子里可能调用转换函数或者构造函数进行类型转换 为了避免ambiguity 使用显示转换

  • 隐式转换最多帮你转一级,因为更多就会产生歧义

  • 隐式转换时候必须保证唯一性,比如有个f(x)一个f(y),同时x和y都可以由int构造成,那么f(1)就gg

    1. Exact match

    2. Match using promotions

    3. Match using standard conversions

    4. Match using user-defined conversions

    5. Mismatch, function undeclared

  • friend的声明位置无所谓private public

  • 一个class的friend可以是另一个class的member function/一个class可以是另一个class的friend class

  • friend只是标明了这玩意存在,而没有真正定义它

  • friend class可以是前面定义过的class,也可以是后面定义、但在当前enclosing scope中定义的class

  • friend function可以是类似friend class的地方定义的,也可以是参数所在enclosing scope中定义的

  • 关于右值引用和拷贝构造 看这里

  • 构造函数前加explicit就可以让这个构造函数只能被显式调用

  • 为了区分是a++还是++a,定义的时候后缀多一个标记用的参数int。a++相当于a.operator++(0)

  • vtbl (v table)虚函数表 vptr虚函数表指针

  • 析构通常都是虚函数

  • virtual void f()=0; 有纯虚函数的就是抽象类

  • class D:public A,private B,protected C{
    //多重继承时要避免两边有一样的东西 二义性
    //继承来继承去可能会生成一个DAG
    }
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13

    * string\<T\>里面的返回值只要写string,到了外面就得string\<T\>

    * 模板的实例化 第一次用到它时候就会把这个类型代进去,过程叫Template instantiation,结果叫specialization。成员函数用到了才会实例化。定义某个指针时候没必要马上把它指向的类型实例化

    * ```c++
    template<typename T,int i,typename compare=std::less<T>>//std::less<T>是默认参数,如果没有就编译错误 compare如果要传入的话 就是传入一个返回值为bool的函数
    class A
    {
    T a[i];
    bool f(T x,T y){return compare(x,y);}
    }
    //i需要是编译期能搞定的值
  • 更特殊的模板会优先选择(我能推出你 你不能推出我) ambiguous会CE

  • 完全特例化complete specialization

    1
    template<> class Vector<void*>{}

    部分特例化partial specialization

    1
    template<typename T> class Vector<T*>:private Vector<void*>{}
  • RAII: Resource Acquisition Is Initialization 已构造的对象最终会销毁,即它的析构函数最终会被调用。函数在正常结束或者throw退出时候都会把局部的东西清掉

  • #include <exception>
    //standard exception 标准库异常