zoukankan      html  css  js  c++  java
  • c++小知识

    • 未初始化的全局变量,程序启动时自动将其全部初始化为0(即变量的每个比特都是0)。
    • 未初始化的局部变量,初始值是随机的。
    • “构造函数”并不负责为对象分配内存空间,构造函数执行时,对象的内存空间已经分配好了,构造函数的作用是初始化这片空间。
    • 使用sizeof运算符技术对象占用的存储空间时,不会将静态成员变量计算在内。      
    #include<iostream>
    using namespace std;
    class Demo{
     int a,b;
     static int c,d;
    };
    int main(){cout<<sizeof(Demo);}

    输出结果:

    8
    
    • 面向对象的程序设计有“抽象”、“封装”、“继承”、“多态”四个基本点。
    • 面向过程的程序设计:数据结构+算法=程序
    • 面向对象的程序设计:类+类+类+······+类=程序
    • 构造函数不能以本类的对象作为唯一参数,以免和复制构造函数想混淆。例如,不能写如下构造函数 
    class A{
       A(A a){······}
    };
    • 以对象作为函数的形参,在函数被调用时,生成的形参要用复制构造函数初始化,这会带来时间上的开销。如果用对象的引用而不是对象作为形参,就没有这个问题了。但是以引用作用形参有一定的风险,因为这种情况下如果形参的值发生改变,实参的值也会跟着改变。如果要确保实参的值不会改变,有希望避免复制构造函数带来的开销,解决办法就是将形参声明为对象的const引用。例如:
    void f(const A&a){}
    • int a[10] 数组地址a 、&a 是一样的,但是 a+1 、&a+1 是不同的,因为a是 int*类型   &a是 int(*)[10] 类型   所以  a+1相当于 a[1]  &a+1相当于 a[10];
    #include<iostream>
    using namespace std;
    void f(int * a) {}
    int main() {
    	int a[10];
    	cout << *a << endl <<
    		a << endl <<
    		&a << endl <<
    		(a + 1) << endl <<
    		(*a + 1) << endl <<
    		(&a + 1) << endl <<
    		*(&a + 1) << endl;
    	    //f((&a))
    
    }
    

      

     输出结果:

    -858993460
    0136FE90
    0136FE90
    0136FE94
    -858993459
    0136FEB8
    0136FEB8

                             示例图片:             

    • 重载运算符“()”、"[]"、"->"、或者赋值运算符"="时,只能将它们重载为成员函数,不能重载为全局函数。
    • 判断好函数的返回值是 bool 或者其他类型。或者string 为“”空。
    •  区分多态和非多态:通过基类指针或引用调用成员函数的语句,只有当该成员函数是虚函数时才会是多态。如果该成员函数不是虚函数,那么这条函数调用语句就是静态联编的,编译时就能确定调用的是哪个类的成员函数
    • c++规定,只要基类中的某个函数被声明为虚函数,则派生类中的同名、同参数表的成员函数即使前面不写virtual关键字,也自动成为虚函数。
    • 多态是通过虚函数表实现的。
    • 在普通成员函数中调用虚函数是多态,但在构造函数和析构函数中调用虚函数不是多态。
    • 有虚函数的类,其析构函数也应该实现为虚函数。
    • 包含纯虚函数的类叫抽象类。不能用抽象类定义对象。抽象类的派生类,仅当实现了所有的纯虚函数,才会变成非抽象类。
    • 用new运算符动态生成的对象都是通过释放指向它的指针来释放的。如果一个基类指针指向用new运算符动态生成的派生类对象,而释放该对象时是通过释放该基类指针来完成的,那么执行的就是基类的析构函数。所以才有了虚析构函数。
    • 每一个函数存储在内存里,因此拥有一个地址,在c++中,指向函数的指针是合法的数据值。
    • list可以有一个所谓的头节点,这个头节点是链表的开始,它指向链表的第一个元素,本身不存储任何东西
      http://bbs.chinaunix.net/forum.php?mod=viewthread&tid=4193458
      头节点不存放数据可以令一些链表操作更方便,比如删除连表中某个节点x: 假设头节点不存放数据: p = head; q = head->next; while (q) { if (q == x) { p->next = q->next; delete x; break; } p = q; q = q->next; } return; 如果头节点存放数据,那删除节点的操作需要单独处理头节点: if (x == head) { head = head->next; delete x; return; } p = head; q = head->next; while (q) { if (q == x) { p->next = q->next; delete x; break; } p = q; q = q->next; } return;

        有这个空的头节点, 只是为了避免:
      1. 插入节点, 每次都要额外判断一下"链表是不是空".
      2. 删除节点, 每次都要额外判断一下"是不是删了头节点".

    • cout<<"xxx";
      

        "xxx"是一个字符串地址 与 char a[3]="yyy"; 的a等同。若是在”xxx“后面加字符 即

      cout<<"xxx"+'*';
      

        此时相当于在”xxx“这个地址上偏移42个字节(*的ASCII码为42)后输出。例如

      #include<iostream>
      using namespace std; 
      
      int main()
      {
      	for(int i=0;i<100;i++)
      	cout <<" "+i;
      	return 0;
      }
      

        输出为

    • static 类成员函数 只要在声明处有 static声明即可,定义不需要static

    • 结构体struct 重载运算符<<

      在结构体内定义  friend ostream & operator<< (ostream &os,const Info info);
      在结构体外定义   ostream & operator<< (ostream &os,const Info info);

        

    • c++一直可以delete空指针
    • 同一个指针不能delete两次,既不能释放了再释放
    •  

      c++不能直接delete的是野指针,会出问题的,所以一般指针被delete之后,最好立即赋值为NULL,以免被再次delete而出现问题。
    • 当明确知道数值不可能为负时,选用无符号类型。
    • 在算术表达式中不要使用char或bool,char在一些机器是有符号的,在另一些机器又是无符号的,所以如果要用char类型,要明确指定是signed char 还是unsigned char。
    • 执行浮点数运算选用double,因为double和float的计算代价相差无几。事实上,对于某些机器,double会比float更快。而long double提供的精度一般是无必要的,且运行时的消耗不容忽视
    • 使用{} (列表初始化)进行初始化且初始值存在丢失信息的危险,则编译器将报错。
    	double a = 123.123;
    	int b { a };
    or
    	double a = 123.123;
    	int b ={ a };
    int b=(a);
    int b(a);则没问题
    • 头文件不应包含using声明,因为头文件的内容会拷贝到所有引用它的文件中去,如果头文件里有某个using声明,那么每个使用了该头文件的文件就都会有这个声明。对于某些程序来说,由于不经意间包含了一些名字,反而可能会产生始料未及的名字冲突
    • vector <int>::size_type;//对
      vector::size_type;//错
      

        

    • vector对象(以及string对象)的下标运算符可用于访问已存在的元素,而不能用于添加元素
    • 迭代器使用递增(++)运算符来从一个元素移动到下一个元素。但因为end返回的迭代器并不实际指示某个元素,所以不能对其进行递增或解引用的操作。 
    • 凡是使用了迭代器的循环体,都不要向迭代器所属的容器添加元素
    • 对数组进行初始化时,会用提供的初始值初始化靠前的元素,剩下的元素被初始化成默认值。
    • 在大多数表达式中,使用数组类型的对象其实是使用一个指向该数组首元素的指针。
    • string和vector也能执行下标运算,但是数组与它们相比还是有所不同。标准库类型限定使用的下标必须是无符号类型,而内置的下标运算无此要求(内置的下标运算符的索引值不是无符号类型),可以处理负值。
    • 	int a = 5;
      	if (a == true)
      		cout << "s";  
      

        因为a不是布尔值,所以进行比较前会首先把true转换成val的类型 在这里会转换成1。所以 if为false

    • 如果程序崩溃,输出缓冲区不会被刷新。即可能代码已经执行了,但输出数据被挂起没有打印唯而已。
    • 当一个fstream对象被销毁时,close会自动被调用。同一个i/of/stream,close后才能重新open另一个文件。
    • 保留被ofstream打开的文件中已有数据的唯一方法是显示指定app或in模式。
    • ifstream关联的文件,默认以 in 模式打开,ofstream 以out  fstream 以in和out。
    • 向一个vecotr、string或deque插入元素会使所以指向容器的迭代器、引用和指针失效,插入到任何位置是合法的,但可能很耗时。
    • 遍历且插入的时候不能用vector<int>::iterator,否则可能因为vector重新allocate内存而地址失效,所以直接使用数组下标。
    • STL 中的vector 以及其他容器 都是 非线程安全的,使用 iterator 迭代器 ,和 插入元素 不进行 加锁控制,会导致严重的问题。
    • vector 的insert 是返回插入的地址
    • 容器元素是拷贝,即非引用参数。
    • 标准库算法(泛型算法)操作的是迭代器而不是对容器进行操作。
    • new出来的动态数组并不是数组类型。
    • char ch;//灾难
      while((ch=cin.get())!=EOF);//从cin.get.()返回的值被转换为char,然后与一个int比较
          cout.put(ch);
      

        不要这样写,c++ primer 中文第五版p675

    • set中判断元素是否相等: 
      if(!(A<B || B<A)),当A<B和B<A都为假时,它们相等。

    • int a[8][5]  跟  int** a 不是同一回事  作为形参时要注意
    • float a[2][2]={0,1,2,3};
      float **p=(float**)a;//强制将二维数组指针转为指向指针的指针

      则此时

      p[0]=0;
      p[1]=1;
      p[2]=2;
      p[3]=3;

      p[0][0]=*(*(p+0)+0)=**p;
      p[0][1]=*(*(p+0)+1);

      p[0][0]  由于*p=0; ====> **p=*(0);  引用地址为零的内存,必然是错误的。

      p[0][1]=*(*p+1)====>*(4),  引用了非法内存

    • fstream 如果没有使用ios::binary标志位,然后进行write/read的话  0a 会变成 0d0a。换行符
    • 	string a = "sadas";
      	const char* p = a.c_str();	
      	cout << p << endl;
      	a = "zxczx";
      	cout << p << endl;
      

        输出是

      sadas
      zxczx
      

        小心string 的c_str()

    • 在debug下编译通过后再转去release。sort 慎用
    • vector resize 是预分配空间,并初始化。后面就能直接用a[100]=10;  reserve不行,会报越界 
    •  sizeof是编译期展开的 ,所以可以得到静态数组的大小,编译期得到静态数组大小 
    • 例2 . 17 中类CB ox 中只有一个成员函数,类CB ox 的对象boxobj 的大小却只有l Byte,
      和空类对象是一样的,所以可以得出,成员函数是不占空间的。

  • 相关阅读:
    apt-clone安装与使用
    利用异或求(整数数组中,有2K+1个数,其中有2k个相同,找出不相同的那个数)
    运行程序,填写结果
    throw与throws的区别
    牛客网多线程程序执行结果选择题
    一个继承了抽象类的普通类的执行顺序
    int i=0;i=i++
    HashMap浅入理解
    &&和&、||和|的区别
    System.out.println()
  • 原文地址:https://www.cnblogs.com/l2017/p/7748673.html
Copyright © 2011-2022 走看看