zoukankan      html  css  js  c++  java
  • C++之乱七八糟<真正的随笔>

    1、new和delete

    int* pi = new int(0);	//把值初始化为0
    A* pA = new A();	       //对于自定义类型,创建对象分两步,第一步分配内存,第二步调用构造函数 A()是构造函数。
    pA->function();delete pA;	 //对于自定义类型,第一步调用析构函数,第二步释放内存。
    int *pi = new int[10];delete []pi;    //申请10个元素的一维数组
    int **pi = new int[5][6];
    delete [][]pi;//申请一个二维数组。
    const int *pci = new const int(1024);
    

    动态创建的 const 对象必须在创建时初始化,并且一经初始化,其值就不能再修改。delete p后,该指针变成悬垂指针,有可能指向内存的任何一个位置。一旦删除了指针所指向的对象,立即将指针置为 0,即指向NULL,这样就非常清楚地表明指针不再指向任何对象

    2、malloc 和 free
    动态内存管理容易出错
    1、删除( delete )指向动态分配内存的指针失败,因而无法将该块内存返还给自由存储区。删除动态分配内存失败称为“内存泄漏(memory leak)”。内存泄漏很难发现,一般需等应用程序运行了一段时间后,耗尽了所有内存空间时,内存泄漏才会显露出来。   delete后要检测一下。
    2、读写已删除的对象。如果删除指针所指向的对象之后,将指针置为 0 值,则比较容易检测出这类错误。
    3、对同一个内存空间使用两次 delete 表达式。当两个指针指向同一个动态创建的对象,删除时就会发生错误。如果在其中一个指针上做 delete 运算,将该对象的内存空间返还给自由存储区,然后接着 delete 第二个指针,此时则自由存储区可能会被破坏。

    3、const用法

    1、定义后左值就不能被修改,所以定义时必须初始化。
    const对象默认为局部变量,若想全局使用,必须显示声明extern。
    文件1  extern const int buffersize=512;  //定义
    文件2  extern const int buffersize;      //使用
    2、const 引用是指向 const 对象的引用 

    const int ival = 1024;const int &refVal = ival; 
    int &ref2 = ival;   //n 非_常引用 指向指向了一个常对象
    const 引用可以初始化为不同类型的对象或者初始化为右值
    int i = 42;         
    const int &r = 42;      //  legal for const references only
    const int &r2 = r + i;    
    
    double dval = 3.14;
    const int &ri = dval;
     
    //编译器会把这些代码转换成如以下形式的编码:   
    int temp = dval;          // create temporary int from the double
    const int &ri = temp;     // bind ri to that temporary 
    

    如果 ri 不是 const,那么可以给 ri 赋一新值。这样做不会修改 dval,而是修改了 temp。期望对 ri 的赋值会修改 dval 的程序员会发现 dval 并没有被修改。仅允许 const 引用绑定到需要临时使用的值完全避免了这个问题,因为 const 引用是只读的。
    3、常指针,指针常量

    const int* p1 = &i;//常量指针,指向一个常量的指针,等同于int const* p1 = &i;
    //*p1 = 2;         //指针指向的内容不能改
    p1 = &j;           //指针可以修改,可以指向别的变量
    int* const p2 = &i;//指针常量,不能修改p2。必须初始化。一个指针,是常量
    *p2 = 2;           //指针指向的内容可以修改,
    //p2 = &j;         //指针不能指向别的变量
    const int* const p3 = &i;//指向常量的常指针
    const int& ri = i;//常量引用,不能修改ri的值。                        
    //ri = 10;    
    i = 10;       OK
    
     

    4、常函数
    //写一个类的时候,尽可能多的声明常函数。以满足常量对象的调用需求。
    int GetN() const   //常函数,在函数内不能修改类的数据成员。
                //编译器解释为 int GetN(const A* this)
                              //必须是类的成员函数常对象只能调用常函数。
    const修饰形参,提高参数传递的效率,保证传入参数不被修改!一般不要返回数据成员的地址或者引用,以免破坏类的封装性。
    const string& GetS() const {return s;}     //用const修饰返回值

    4、static
        int i;                 //实例成员,属于对象,每个对象都有自己的一份拷贝,只能通过对象访问
        static int j;        //静态成员,属于类,所有对象共享一份数据。可以通过对象名或者类名访问。
        int A::k = 0;     //静态成员需要在类外初始化
        static void function();   //静态成员函数:无this指针,不能访问类的实例成员,只能访问类的静态成员。

    5、初始化
       int ival(1024);     // 直接初始化则是把初始化式放在括号中【更灵活效率更高】
       int ival = 1024;    // 复制初始化语法用等号(=)
        初始化列表
        A::A() : i(2),j(3),k(10){......}A::A(int a,int b):i(a),j(b){}   //A的私有数据成员i,j 

    6、类

    1.构造函数Student 的私有成员m_ID,m_cName

    Student::Student(char *pName, int ssId)
    {
    	m_ID = ssId;
    	strcpy(m_cName, pName);
    	cout << "construct new student" <<endl;
    }
    

    2.拷贝构造函数  

    Student::Student(const Student& Stu)
    {
    	m_ID = Stu.m_ID;
    	strcpy(m_cName, Stu.m_cName);
    	cout << "construct copy of" << Stu.m_cName << endl;
    }
    

    3.浅拷贝  自己不定义,C++默认的拷贝构造函数深拷贝  
    Student::Student(Student& stu)
    {
    	cout <<"Constructing " <<stu.pName <<endl;
    	pName=new char[strlen(stu.pName)+1];
    	if(pName!=0)
    	{
    		strcpy(pName, stu.pName);
    	}
    }
    

    7、域名空间
    namespace N1{void F(){}}   //自定义
    useing namespace N1;    F();  /调用
    或者N1:: F();

    8、函数参数缺省
    int add ( int x,int y = 5,int z = 4 );  Y   
    int add(int x = 3,int y,int z);   N
    缺省参数(default value)由后向前

    9、传递指向指针的引用
    void ptrswap(int *&v1, int *&v2)  //int *&v1理解为v1是一个引用,与指向int型对象的指针相关联。
    { 
        int *tmp = v2;                 //也就是说,v1 只是传递进 ptrswap 函数的任意指针的别名。
        v2 = v1;
        v1 = tmp;   
    }         //使用的时候用指针ptrswap(pi1,pi2)
    

    10、头文件
    1、头文件用于声明而不是用于定义
    2、定义const 对象
    3、inline函数
    11、静态联编与动态联编 

    calss A{public:void f(){cout<<"a";}};
    class B:public A{public:void f(){cout<<"b";}};
    class C:public A{public:void f(){cout<<"c";}};
    class D : public A{};   //没有重写,继承父类的函数,也是抽象类,不能实例化。(该例子是动态联编的)
    void Test(A& ra){
    ra.f();//取决于调用f1的引用或者指针的声明类型。叫做静态联编,也就是编译时已经确定了会执行哪个函数体。
    }
    void main(){
    	B b;
    	A& ra = b;	
    	ra.f();        //输出a
    	A* pa = &b;
    	pa->f();      //输出a
    	Test (b);     //输出a     //如果A类的前面加上virtual ,则变成动态联编,这时输出b;
    }      
    

    12、动态联编条件:1.用基类的引用(指针)指向派生类的对象 2.只有调用虚函数,才有动态联编的效果。 

    class A                    // 抽象类:含有纯虚函数的类。不能实例化。
    {
    public :virtual void f1() {cout << "A f1" << endl;}	//父类中声明纯虚函数
    };
    如果一个类有可能作为基类,那么需要把它的析构函数写成虚函数。派生类的析构函数自动成为虚函数

    13、指针
    1、指针使用前要初始化!!!!
    ---->运行时的错误如果使用未初始化的指针,会将指针中存放的不确定值视为地址,然后操纵该内存地址中存放的位内容。使用未初始化的指针相当于操纵这个不确定地址中存储的基础数据。因此,在对未初始化的指针进行解引用时,通常会导致程序崩溃。
    2、特殊的指针类型 void*,它可以保存任何类型对象的地址
    3、指向指针的指针

    //定义:
     int *pi = &i;
     int **ppi =π
    
    使用:解引用2次
    cout<<**ppi<<endl;
    
    4、指针和数组:
    int *ip = ia;       // ip 指向ia[0] ia是一个数组名。
    int *ip2 = ip + 4;  // ok: 指针+4,则直至后移4个单位,然后赋值给指针ip2,注意不要越界
    
    指针还支持减操作
    int last = *(ia + 4)   //取数组的第四个元素,解引用后赋值给last
    int last = *ia + 4     //取数组第一个元素,解引用后+4
    

    指针和下标
    int *p = &ia[2];     // ok: p 指向数组ia的第2个元素
    int j = p[1];        // ok: p[1] 相当于 *(p + 1),即ia[3]
    int k = p[-2];       // ok: p[-2] 相当于ia[0]
    
    指针遍历数组    -------指针相当于数组的迭代器
    const size_t arr_sz = 5;
    int int_arr[arr_sz] = { 0, 1, 2, 3, 4 };//pbegin指向数组第一个元素,pend指向最后一个元素
    for (int *pbegin = int_arr, *pend = int_arr + arr_sz;pbegin != pend; ++pbegin)
          cout << *pbegin << ' '; // 输出当前对象
    
    14、位操作符    
    unsigned char               bit1 = 0227      //10010111   
    ~  bitwise NOT(位求反)    bit2=~bit1;      //01101000 
    <<  left shift(左移)      bit1<<1          //00110110  整体左移,右侧补0
    >>  right shift(右移)     bit1>>2          //00100101  整体右移,左侧补0
    &  bitwise AND(位与)      和bit逐位取与操作
    ^  bitwise XOR(位异或)    和bit逐位取异或操作
    |  bitwise OR(位或)       和bit逐位取或操作
    

    15、自增自减运算符 
    后置++  a++;

    cout<<*p++<<endl;  等价于  cout<<*p<<endl;++p;
    
    16、使用预处理进行调试
    int main()
    {
       #ifndef NDEBUG
       cerr << "starting main" << endl;
       #endif
    }
    
    int main(){   #ifndef NDEBUG   cerr << "starting main" << endl;   #endif}如果 NDEBUG 未定义,那么程序就会将信息写到 cerr(输出到控制台)中。如果 NDEBUG 已经定义了,那么程序执行时将会跳过 #ifndef 和 #endif 之间的代码。

  • 相关阅读:
    Python 安装Twisted 提示python version 2.7 required,which was not found in the registry
    Openfire Strophe开发中文乱码问题
    css div 垂直居中
    How to create custom methods for use in spring security expression language annotations
    How to check “hasRole” in Java Code with Spring Security?
    Android 显示/隐藏 应用图标
    Android 当媒体变更后,通知其他应用重新扫描
    文件上传那些事儿
    专题:点滴Javascript
    主流动画实现方式总结
  • 原文地址:https://www.cnblogs.com/flysnail/p/2055426.html
Copyright © 2011-2022 走看看