• C++ notebook


    ~1 库
    
    写xx.h库时
    #ifndef _xx_h
    #define _xx_h
    
    
    #endif _xx_h
    
    //确定xx.h库一共只被调用一次,引用库相当于把库中的代码复制过来
    
    
    ~2 友元
    
    class node{
    private:
    	int G1,G2;
    	friend void work();//申明work函数是友元,可以调用node类里的私有变量
    public:
    	node(int _G1=0,int _G2=0){G1=_G1,G2=_G2;}
    }G;
    int work(){
    	return G.G1+G.G2;
    }
    
    
    
    ~3 运算符重载 (4种方法) (operator +)
    
    method 1 (局部重载)
    class node{
    private:
    	int G1,G2;
    public:
    	node(int _G1=0,int _G2=0){G1=_G1,G2=_G2;}
    
    	node operator +(const node b){return node(G1+b.G1,G2+b.G2);}
    	/*
    	node operator +(const node b)const {return node((*this).G1+b.G1,(*this).G2+b.G2);}
    	//直接在里面调用G1,G2,相当于(*this).G1,(*this).G2
    	*/
    }G;
    
    method 2 (局部重载)
    class node{
    private:
    	int G1,G2;
    public:
    	node(int _G1=0,int _G2=0){G1=_G1,G2=_G2;}
    	node operator+(const node b);
    }G;
    node node::operator +(const node b){return node(G1+b.G1,G2+b.G2);}
    //相当于先定义要重载运算符,再在下面重载
    
    method 3 (全局重载)
    class node{
    private:
    	int G1,G2;
    public:
    	node(int _G1=0,int _G2=0){G1=_G1,G2=_G2;}
    	friend node operator +(const node a,const node b);
    }G;
    node operator +(const node a,const node b){return node(a.G1+b.G1,a.G2+b.G2);}
    //友元的作用是让重载时能调用到G1,G2,若是G1,G2在public中可以不用开友元
    
    method 4 (全局重载)
    class node{
    private:
    	int G1,G2;
    public:
    	node(int _G1=0,int _G2=0){G1=_G1,G2=_G2;}
    	friend node operator +(const node a,const node b){return node(a.G1+b.G1,a.G2+b.G2);}
    }G;
    //相当于把method3的重载和开友元合并到一起来写,算是重载运算符的特殊写法
    
    /*
    全局重载 vs 局部重载
    即 重载全局函数 vs 重载成员函数
    
    2+node(2,3)时,全局重载会默认先把2类型转化成node(2),可以过编译
    			而局部重载则过不了编译
    */
    
    
    
    ~4 重载运算符 += ++ >> << [] =
    
    class node{
    friend istream& operator >>(istream &in,node &G);//给它开友元
    friend ostream& operator <<(ostream &out,const node &G);//给它开友元
    //必须开全局变量
    //可以合在一起写
    private:
    public:
    	int G1,G2;
    	int s[10],*p;
        node(){G1=0,G2=0,p=new int;}
        node(int _G1,int _G2){G1=_G1,G2=_G2,p=new int;}
    	~node(){delete p;}
    	node &operator +=(const node &b){
    		(*this)=node(G1+b.G1,G2+b.G2);
    		return *this;
    	}
    	// int下 a+=b <==> a=a+b <==> a加上b 并且 返回值为a
    
        int &operator[](int x){return s[x];}//函数名前加& 可以左值调用,相当于return后面的参数
    
    	node &operator=(const node &x){
    		if(this==&x)return *this;//一定要判=左右是否相等,不然下面delete指针会使代码出错
    		delete p;
    		p=new int;
    		*p=*x.p;
    		G1=x.G1,G2=x.G2;
    		for(int i=0;i<10;i++)s[i]=x.s[i];
            return *this;
    	}
    	
    	node& operator++(){//重载 前缀++
    		G1++;
    		return *this;
    	}
    	node operator++(int x){//x为形式参数,无意义,表示重载 后缀++
    		node tmp;
            tmp=*this;
            //这里不能合写成node tmp=*this,因为这相当于直接构造tmp,用的是默认的赋值,写了node(node &G){}的构造函数才可以合写
    		G1++;
    		return tmp;
    	}
    	//函数名前加&,表示反回的是tmp的地址(左值)而不是右值
    	//前缀++A,前缀--A,+=,-=函数名前面都要加&
    	//后缀A++,后缀A--函数名前面不能加&
    };
    istream& operator >>(istream &in,node &G){//流读入
        // cout<<"####"<<endl;
        in>>G.G1>>G.G2;
        return in;
    }
    ostream& operator <<(ostream &out,const node &G){//流输出
        // cout<<G.G1<<" "<<G.G2<<endl;
        out<<G.G1<<"/"<<G.G2;
        return out;
    }
    //流输入时G前面不能加const,不然不能修改G了
    //流输出时G前面加了const,则G传进来的可以是左值或右值,不然右值不能传进来,因为计算机可能认为G会被修改,但右值是不能被修改的
    
    
    ~5 类 函数写法
    
    **
    class node{
    private:
    	int G1,G2;
    public:
    	node(int _G1=0,int _G2=0){G1=_G1,G2=_G2;}
    	int calc(){
    		return G1+G2;
    	}
    }G;
    
    
    **
    class node{
    private:
    	int G1,G2;
    public:
    	node(int _G1=0,int _G2=0){G1=_G1,G2=_G2;}
    	int calc();
    }G;
    int node::calc(){
    	return G1+G2;
    }
    
    //以上两种写法等价,一般大工程题采用第二种先申明后定义的方式,看着更清晰(即函数的先申明后定义)
    
    
    ~6 类 构造函数和析构函数
    
    //构造函数为生成类时自动调用的,析构函数为函数消亡时自动调用的
    class node{
    private:
    	int G1,G2;
    	int *p;
    public:
    	node(){G1=10,G2=2;}
    	node(int _G1){G1=_G1,G2=1000;}
    	
    	
    	node(int _G1,int _G2){G1=_G1,G2=_G2;}//以上三个都为构造函数,传入参数数量或类型不同
    	//or
    	node(int _G1,int _G2):G1(_G1),G2(_G2){}//先令G1=_G1,G2=_G2,在调用括号里的代码
    	
    	
    	//如果没有自定义构造函数,系统将自动生成一个默认构造函数 node(){} ,所有元素一开始都为随机值
    	//如果同时被匹配上多个同名函数/构造函数,则会报错
    	~node(){delete p;}//如果类中存在指针,在程序运行过程中可能有p=new int,所以要把内存释放,不然会内存泄漏
    	//如果没有自定义析构函数,系统将自动生成一个默认构造函数 ~node(){} ,表示什么也不做
    }G;
    
    ~7 指针
    
    int *p,*q;
    int a=3,b[3];
    p=&a;//取a的地址,p指向了a
    q=b;//b其实记录的是数组b[3]的首地址,这里把b的地址赋值给了q,相当于可以用q调用b数组,q[i]与b[i]相同
    
    int *p=new int;//动态申请内存
    delete p;
    int *q=new int[10]//申请了一个数组,q指向其首地址,可以把q[i]当成数组看
    delete[] q;
    //指针指向下一个地址或程序结束时,一定要把空间回收掉,不然会内存泄漏
    
    
    int *p[10];//指针数组
    for(int i=0;i<10;i++)p[i]=new int[10];
    for(int i=0;i<10;i++)for(int j=0;j<10;j++)p[i][j]=1;
    for(int i=0;i<10;i++)delete[] p[i];
    //申请二维数组
    
    
    int **q;//多级指针
    q=new int*[10];
    for(int i=0;i<10;i++)q[i]=new int[10];
    for(int i=0;i<10;i++)delete[] q[i];
    delete[] q;
    //申请二维数组
    
    
    int &j=i;//j可以引用i,即j成为了i的别名,调用j就相当于调用i
    //定义引用类型的变量时必须立即对它初始化,不能写成 int &j;j=i
    
    void F(int x,int y){
    	cout<<"!!!"<<x<<" "<<y<<endl;
    }
    int main(){
    	void (*p)(int,int);//函数指针 void表示函数返回类型,(int,int)表示传入参数类型
    	p=F;//表示p指向F函数的入口地址,即以下可用p代替F
    	p(2,3);
    	return 0;
    }
    
    
    const int *p=new int;//不能改*p的值
    int *const p=new int;//不能改p指向的地址
    
    
    
    ~8 template模板
    
    template<class T>
    T Add(T a,T b){return a+b;}
    
    template<typename T>//这里class和typename等价,但建议写typename以和类class区分
    T Add(T a,T b){return a+b;}
    
    template<typename T>
    class node{
    public:
    	int x,*p;
    	T G;
    	T Work(T x,T y){
    		return x+y;
    	}
    };
    int main(){
    	node<int> A;//一定要申明T的类型(此处为int)
    	node<int> *B=&A;
    	A.x=1;
    	B->x=1;//这两种用法等价,单纯的node类型用".",指针用"->"
    	// !!!   B->x就是(*B).x
    	
    	A.p=new int;
    	B->x=new int;//二者等价
    
    	*(A.p)=3;
    	*(B->x)=3;//二者等价,*放最外面
    	return 0;
    }
    
    
    
    ~9 可变参数模板 ...
    
    #include<bits/stdc++.h>
    using namespace std;
    void debugPrint(){cout<<endl;}//最后还要写一个传入变量数为0的函数
    template<typename T,typename ...T2>
    void debugPrint(T a,T2... b){//T2... b表示传入多个变量(变量数为>=0的任意个)
    	cout<<a<<" ";
    	debugPrint(b...);
    }
    int main(){
    	std::string str("test message");
    	debugPrint("Hello, Happy World!", 19260817, false, str);
    	debugPrint("debug");
    	return 0;
    }
    
    ~10 main函数传参数
    
    int main(int agrc,char *agrv[]){
    	cout<<agrc<<endl;
    	for(int i=0;i<agr;i++)cout<<agrv[i]<<" ";cout<<endl;
    	return 0;
    }
    //传参进去的变量名称并不是限制死为agrc和 *agrv[],也可以改成如以下的写法
    int main(int num,char *nmdp[]){
    	cout<<num<<endl;
    	for(int i=0;i<agr;i++)cout<<nmdp[i]<<" ";cout<<endl;
    	return 0;
    }
    /*
    命令行输入
    ./a 233 abc
    
    程序输出
    3
    ./a 233 abc
    */
    
    
    
    ~11 Lambda表达式 最简单应用
    bool cmp(pp x,pp y){return x.fi+x.se<y.fi+y.se;}
    int main(){
    	sort(a+1,a+n+1,cmp);
    }
    
    可改为
    
    int main(){
    	sort(a+1,a+n+1,[](pp x,pp y)->bool{return x.fi+x.se<y.fi+y.se;});
    }
    //[]内先不考虑,()内表示传入参数,bool表示函数返回值,{}内为函数主体
    //像sort一样很多系统自带函数支持Lambda表达式
    
    int a[5],b=3;
    auto func = [=](int x,int y)->int {return x+y+b+a[1];};
    cout<<func(a[2],a[1])<<endl;
    /*
    //相当于把该Lambda表达式存到func里,func必须为auto类型
    Lambda表达式可以捕获Lambda可见范围内的所有变量
    [=]       表示捕获的变量为值传入
    [&]       表示捕获的变量为地址传入
    [&a]      表示捕获变量a用地址传入
    []        表示不能捕获变量
    [=,&b,&c] 表示捕获变量b,c时地址传入,其他为捕获其他变量为值传入
    [&,b,c] 表示捕获变量b,c时值传入,其他为捕获其他变量为地址传入
    若为值传入,捕获的值为Lambda创建时捕获的值,而非使用时再次去捕获
    */
    
    ~12 && 右值引用
    
    /*
    值- 左值
     \
       右值- 纯右值
           \
    		 将亡值
    */
    
    class node{
    public:
    	int *p;
    	node(){}
    	node(node &&_G){p=_G.p;_G.p=nullptr;}
    	/*
    	&& 表示传入右值(这段代码下面传入的是将亡值)
    	右值自身不能被调用地址,即不能写成*this=G这种形式,所以主要一般是用在 直接把其内部指针的地址复制过来
    	//由于是将亡值,所以在复制地址完之后 应该在它消亡前把动态指针地址改成nullptr,防止其被delete掉
    	右值引用的目的主要是为了是减少内存拷贝,优化性能
    	*/
    };
    node Fun(){
    	node S;
    	S.p=new int[10];
    	for(int i=0;i<10;i++)S.p[i]=i;
    	return S;
    }//此处返回的是将亡值
    int main(){
    	node G(move(Fun()));//给G赋初值时传入的是一个右值(将亡值)   move(x)表示将x强行转换成右值
    	for(int i=0;i<10;i++)cout<<G.p[i]<<" ";
    	cout<<endl;
    	return 0;
    }
    /*
    输出结果为:
    0 1 2 3 4 5 6 7 8 9
    */
    
    
    ~13 组合和继承
    
    //组合--将point当成line的成员函数
    class point{
    	int x,y;
    };
    class line{
    	point a,b; //point a,b被称为对象成员
    };
    
    //继承--将point的代码继承到point2中,继续新添加功能
    class node{
    private:
        int a;
    protected:
        int b;
    public:
        int c;
    }
    class node2:public node{//public继承
    
    };
    
    //private:只能被当前类中的成员函数访问
    //protested:只能被当前类和派生类中的成员函数访问
    //public:可以被所有函数访问
    
    //private继承:将基类的public类型变成private类型,基类的protected类型仍为private类型(相当于与private取min)
    //protected继承:将基类的public类型变成protected类型后继承(相当于与protected取min)
    //public继承:完全继承基类(相当于与public取min)
    //ps:无论是哪种继承方法,基类中的private都不能被继承
    
    //派生类调用构造函数时:先调用基类的构造函数,再调用对象成员(如果存在)的构造函数,最后调用自己的构造函数
    //派生类调用析构函数时:先调用自己的析构函数,再调用对象成员(如果存在)的析构函数,最后调用基类的析构函数
    
    
    class node{
    public:
        int a;
        int b;
        int c;
        node(int _a=0,int _b=0,int _c=0):a(_a),b(_b),c(_c){cout<<"new node   "<<a<<" "<<b<<" "<<c<<endl;}
    	~node(){cout<<"end node"<<endl;}
    	int F(){return a;}
    	node &operator=(const node &other){
    		if(this==&other)return *this;
    		a=other.a,b=other.b,c=other.c;
    		return *this;
    	}
    };
    class node__{
    public:
        int a;
        node__(){cout<<"new node__"<<endl;}
    	~node__(){cout<<"end node__"<<endl;}
    };
    class node2:public node{
    public:
        int G;
    	node__ A;
        node2():node(1,2,3){cout<<"new node2"<<endl;G=4;}//先调用node(1,2,3),再调用node__的构造函数,最后调用括号里的
    	or
    	node2(){cout<<"new node2"<<endl;G=4;}//等价于 node2():node(){cout<<"new node2"<<endl;G=4;}  调用node()默认构造函数
    
    	~node2(){cout<<"end node2"<<endl;}//先调用括号里的,再调用node__的析构函数,最后调用node的析构函数
    	int F(){return G;}//此函数F()与基类中F()名称与调用类型完全相同,此时认为是派生类里的新函数覆盖了基类里的旧函数
    	node2 &operator=(const node2 &other){
    		if(this==&other)return *this;
    		G=other.G,A=other.A;
    		node::operator=(other);
    		//调用基类的赋值函数,尽管other是个node2类型,但这样调用会把other的基类传进去(C++规定派生类函数能自动转化成基类函数)
    		return *this;
    	}
    };
    /*
    调用node2 A; 输出如下
    
    new node   1 2 3
    new node__
    new node2
    end node2
    end node__
    end node
    or
    
    new node   0 0 0
    new node__
    new node2
    end node2
    end node__
    end node
    */
    
    
    
    
    ~14 多态性、虚函数、纯虚函数、抽象类
    
    //编译时的多态性
    int f(){return 1;}
    int f(int x){return 2;}
    
    //编译时的多态性
    int operator+(int a,int b){return a+b;}
    int operator+(pp a,pp b){return pp(a.fi+b.fi,a.se+b.se);}
    
    
    //运行时的多态性
    class Shape{
    public:
        virtual double S(){return 233;}//前面加virtual,定义虚函数
    	virtual ~Shape(){}
    	/*析构函数前面务必加上virtual(一定要写带virtual的析构函数)
    	加上virtual后,一个基类的指针指向派生类,其消亡时本来只会调用基类的消亡函数
    	但基类的消亡函数前面如果带了virtual,它会先去调用派生类的消亡函数,再来调用基类的函数
    	*/
    };
    class Circle:public Shape{
    public:
        double r=1;
        virtual double S(){return pi*r*r;}//此处前面virtual可以不加
    };
    class Rectangle:public Shape{
    public:
        double a=2,b=3;
        virtual double S(){return a*b;}//此处前面virtual可以不加
    };
    int main(){
        Circle A;
        Rectangle B;
        Shape *p=&A,*q=&B;
        cout<<p->S()<<" "<<q->S()<<endl;
    	/*
    	本来p是一个Shape的指针,其指向派生类,只能调用派生类的基类的成员
    	但S()变为虚函数后,将先在派生类中找同名函数(名称和参数类型都相同),若存在则调用派生类中的函数,找不到则调用原函数
        */
    
    	Shape *t=new Circle;
    	delete t;
    	/*
    	由于Shape的析构函数前面带了virtual,此时先调用Circle的析构函数,再调用Shape的基类函数
    	Circle的析构函数会把new Circle开的Circle类中的a,b的空间释放掉
    	所以用类来写多态时,基类函数前面一定要带virtual
    	*/
    	return 0;
    }
    
    /*
    输出为 : 3.14159 6
    
    若将virtual去掉,输出为: 233 233
    */
    
    virtual double S(){return 233;}//虚函数
    virtual double S()=0;//纯虚函数
    /*
    将上面改成下面后上述代码也成立
    区别:如果一个函数具有至少一个纯虚函数,则其被称为抽象类,抽象类可以创建指针(如Shape *p),但不能创建该类对象(如Shape C)
         因为类中有纯虚函数,其为未定义完全的函数
    */
    
    
    
    
    ~15 文件输入输出
    ofstream out("1.in");//另一个名为out的输出文件流和1.in相关联,此时会自动先清空1.in(若1.in不存在会新建一个)
    out<<1<<" "<<2<<endl;//将1 2写入到out缓冲区,endl会自动将当前缓冲区的内容读入到1.in中
    out.close();//关闭out和1.in文件的关联,并将out缓冲区剩下的内容全部读写入1.in
    out.open("2.in")//可以令out再与2.in相关联
    ...
    out.close();
    
    ifstream in("1.in");//另一个名为in的输入文件流和1.in相关联(若1.in不存在不会新建)
    int a,b;
    in>>a>>b;//从1.in中读入
    cout<<a<<" "<<b<<endl;
    in.close();	//关闭out和1.in文件的关联
    
    fstream io("1.in");//创建一个名为io的输入输出文件流,令其与1.in相关联
    in.seekp(4);//找到1.in中第4个字节的位置,从这里开始读入或更改(0-base)   ( 默认为从头开始,即in.seekp(0) )
    int a,b;
    in>>a>>b;//依次读入两个整数
    in<<a<<b;//接着写入两个整数,直接将1.in中相应位置给替换掉,Ascii文件存储 233333算6个字符类型,而不是一个整数类型,占6个字节
    io.close();
    
    fstream io("1.in",fstream::in);//io相当于一个ifstream类型
    fstream io("1.in",fstream::out);//io相当于一个ofstream类型
    
    //判断文件是否读完:
    while(in>>x){}
    while((ch=in.get())!=EOF){}//读接下来一个字符放到ch中,ch为char
    while(!in.eof()){in.read(ch,5);}//读入接下来5字节放到x中,ch为char*
    
    
    ofstream out("1.in");
    for(int i=1;i<=10;i++)out.write(reinterpret_cast<const char*>(&i),sizeof(int));//表示用1.in中数据用二进制文件存储(这里一个i占4字节)
    out.close();
    fstream in("1.in");
    int x;
    in.read(reinterpret_cast<char*>(&x),sizeof(int));//从二进制文件中读取数据
    while(!in.eof()){
    	cout<<x<<" ";
    	in.read(reinterpret_cast<char*>(&x),sizeof(int));//从二进制文件中读取数据
    }
    in.close();
    
    //采用二进制文件存储,可方便的用fstram类型定向修改某一位置的值
    
    
    
    ~16 函数指针
    int calc(int a,int b){return a+b;}
    int (*p1)(int,int); //返回类型(*指针变量)(形式参数表)
    p1=calc;//让p1指向名为calc的函数
    cout<<p1(3,4)<<endl;//等价于调用calc(3,4)
    //or
    cout<<(*p1)(3,4)<<endl;//等价于调用calc(3,4)
    
    
    
    ~17 模板的特定实例的友元
    
    template<typename T1>class node;
    template<typename T1>
    class node2{
    	template<typename T1> friend class node;//所有node类模板都为友元
    	friend class node<T1>;//申明只有当node类 模板为int类型的特定实例 才为友元
    };
    
    
    
    
    ~18 异常处理 try throw catch
    
    class Error1{//定义一个异常类Error1
    public:
        void Output(){cout<<"error1"<<endl;}
    };
    class Error2{//定义一个异常类Error2
    public:
        void Output(){cout<<"error2"<<endl;}
    };
    class Error3{//定义一个异常类Error3
    public:
        void Output(){cout<<"error3"<<endl;}
    };
    void G(){
        throw Error3();//异常抛出,此处零时用构造函数构造一个Error3类的对象,将它抛出
    }
    int main(){
        try{
            try{
                cout<<"1"<<endl;
                G();//此处已经throw,直接跳出当前try下面第一个捕获到它的catch,并调用当前已定义变量的析构函数
                throw Error1();
                throw Error2();
                cout<<"2"<<endl;
            }
    		//try后面要紧跟catch,中间不能有其他代码
            catch(Error1 tmp){//此处未捕获到,继续跳出(若是不需要用到tmp,也可只定义要捕获的类型Error1)
                tmp.Output();
            }
        }
        catch(Error2 tmp){//未捕获到,继续向下
            tmp.Output();
        }
        catch(...){//捕获剩余所有抛出的异常
            cout<<"other Error"<<endl;
        }
        cout<<"3"<<endl;
        return 0;
    }
    
    /*
    输出:
    1
    other Error
    3
    */
    
    
    
    ~19 静态成员与静态成员函数(例外:静态常量成员) static
    
    class A{
    private:
        int x;
        static int rate;//开了一个静态成员,为类A的所有对象共享
        static const int GGG=20;//开了一个静态常量成员,每个对象单独开,必须在类定义时直接初始化
    public:
        A(int _x=0):x(_x){}
        static void Set_rate(int x){rate=x;}//静态成员函数,用来访问静态成员(或其他静态成员函数)
        int Get(){return x*rate;}
    };
    int A::rate=2;//为该静态成员申请空间,需要且仅需要申请一次
    //静态常量成员是例外,不需要申请空间,其储存在类的对象中
    int main(){
        A a(2),b(3),c(4);
        A::Set_rate(3);//调用类A中的静态成员函数,以修改静态成员rate
        cout<<a.Get()<<endl;
        cout<<b.Get()<<endl;
        cout<<c.Get()<<endl;
        return 0;
    }
    
    /*
    输出:
    6
    9
    12
    */
    
    
    
    ~more
    
    /*
    C++中,赋值是一种运算,返回值是左边对象
    类是更合理的库
    类没定义private还是public,默认是private
    delete对象可以为空指针
    不能delete一个地址两次
    空指针p不能调用*p(若为node *p,p=nullptr,p不能调用node中的变量)
    判断p!=nullptr常数极大(事实如此)
    
    
    int Get(){return a.x;}
    friend bool operator==(const Calendar& a,const Calendar& b){return a.Get() == b.Get();}
    可能过不了编译,因为a,b前面加了const,而系统认为a.Get()可能会改变a,b的内部变量
    所以应该再改成
    int Get()const{return a.x;}//加上const
    
    size_t 为unsigned int(32位机子)/unsigned long long(64位机子)
    在类里面,函数可以直接调用在它下面写的函数,而不用在前面先定义
    
    
    to_string(x) 将整数/浮点数类型的x转化成string
    
    class A{
    public:
    	class B{
    
    	};
    };
    B叫做嵌套类,和A没有任何关系(即B中元素不能调用A中private的元素),只是A可以调用它。如果class B定义在public中,相当于定义在外面
    */
    
    ~more more
    
    /*
    1.
    0开头为8进制
    0x开头为16进制
    
    2.
    cout<<"1as\023";读到\0为止
    cin>>s;//char *s 读入最后会加入\0
    
    3.
    特定只能重载成成员函数不能重载成友元函数的4种操作符: =,(),[],->
    特定只能重载成友元函数不能重载成成员函数的操作符: <<,>>
    
    4.不能解引用空指针
    
    5.
    char s[10];
    sizeof(s) =10 数组所占字节大小
    char *s=new char[10];
    sizeof(s) =4/8 指针所占字节大小(因为计算机不确定新开空间的具体大小)
    
    strlen(s) 往后数到\0为止
    
    6.
    int const *p=new int;
    const int *p=new int;
    int *const p=new int;
    前两种相同指针不能修改指向地址的值
    第三种指针不能修改指向地址
    
    7.
    程序代码不能有二义性
    尤其注意隐式转换
    
    8.
    cin.getline(s,10,'.');
    cin.get(s,10,'.');
    区别为get读到'.'结束后,'.'仍存在于输入流中
    而getline读到'.'结束后,结束符'.'从输⼊流中被删除
    
    9.
    cout<<"\141"; 即输出a (97=64*1+8*4+1,8进制)
    cout<<"\60"<<"\060"; 即输出两个0(48=8*6,8进制)
    cout<<"\t"; 即输出tab
    
    10.
    int *p=new char[10] 动态开出的数组最后要手动加上\0
    
    11.
    class node{
        int a,b;
    public:
        node(int _a=0,int _b=0):a(_a),b(_b){}
        operator int() const{return a+b;}//类型转换,可用int(G)把G从node类型转化成int类型
    };
    
    12.
    隐函数转换时不能存在二义性
    class node{
        int a,b;
    public:
        node(int _a,int _b):a(_a),b(_b){}//普通构造函数
    	node(const node &tmp){a=tmp.a,b=tmp.b;}//拷贝构造函数
        node(int x=0){a=x,b=x;}//转换构造函数
        node operator +(const node x)const{
            node tmp(a+x.a,b+x.b);
            return tmp;
        }
        operator int() const{return a+b;}//类型转换函数
    };
    int main(){
        node G(3,4);
        int x=2;
        G+x;//这里有两种可行的隐函数转换,要么将G从node转成int,要么从将x从int转成node
    	//从而这里会编译报错
        return 0;
    }
    
    13.
    同时编译多个文件
    g++ a.cpp b.cpp -o a
    
    注意:a.cpp和b.cpp中只能有一个main函数
    某一源文件中变量/函数/类前面加了static,则该变量/函数/类只能在该源文件中使用
    不然,可以通过在另一源文件中加形如extern int a;/extern void init(); 的代码使得另一源文件也可以调用该变量/函数
    不过extern的变量只能在其他源文件中一共定义一次(不算static)
    ps:申明函数和类前面可以不加extern,加/不加是等价的
    
    使用#include某一个库,相当于手动把源文件链接起来(显然不能相互引用形成环),最后形成森林一样的结构
    
    14.
    内联函数不能递归
    
    15.
    尾置返回
    
    void init(){}
    可以写成
    auto init()->void{}
    //使用尾置返回时前面要带个auto
    
    lambda表达式要使用尾置返回
    
    
    16.
    class node{
    
    public:
    	void calc(const node a)const{//前一个const表示该函数不能修改a,后一个const表示cosnnt不能修改*this
    
    	}
    }
    
    
    17.
    void calc(const int &x){}
    
    calc(3);//可以这样调用,可以当作给3这个常量开了个静态存储区,调用时虽然取地址了,但前面有个const,保证了其不会被修改
    
    
    18.
    class node{
    	static const int x=2;//直接在类里面赋初值
    	static int y;
    	const int z;//可以选择不直接赋初值,而是在构造函数的初始化列表中赋初值
    	node():z(3){}
    };
    int node::y=2;//要在外面定义+赋初值
    
    19.
    explicit:构造函数不能使用必须为显示转换,不能为隐式转换
    
    class node{
    private:
        int a;
    public:
        explicit node(int _a=0):a(_a){}
    };
    int main(){
        node A;
        A=2;//编译报错,因为这里用到了int到node的隐式转换,但上面定义时写了explicit,要求必须为显示转换
    	A=node(2);//正确
        return 0;
    }
    
    
    20.
    int a=22;//10进制
    int a=0x22;//0x开头为16进制
    int a=022;//0开头为8进制
    
    21.
    char s[]="abb";//相当于开了个s[4],s="abb\0"
    
    22.
    char中'\0'的Ascii码为0
    
    23.
    strcpy(a,b) 拷贝到\0为止,\0也会被拷贝过去
    
    24.
    void solve(base x){//此处调用拷贝构造函数,而不是赋值"="  (若没有定义拷贝构造函数,系统会产生一个默认的拷贝构造函数)
        return;
    }
    int main(){
        base x;
        solve(x);
        return 0;
    }
    
    25.
    cout<<setw(8)<<setfill('#')<<endl;//setw下一次有效,setfill永久有效
    
    
    
    */
    
  • 相关阅读:
    canvas绘制折线路径动画
    canvas绘制虚线图表
    BootstrapTable 行内编辑解决方案:bootstrap-table-editor
    canvas绘制图像轮廓效果
    三维场景中常用的路径动画
    三维组态部件动画解决方案
    canvas多重阴影发光效果
    萌新的算法课-方法论
    网易云ncm文件转换器
    PyCharm永久激活
  • 原文地址:https://www.cnblogs.com/zhongzero/p/16081037.html
Copyright © 2020-2023  润新知