C++笔记(3):一些C++的基础知识点

 

      前言:c++

      找工做须要,最近看了下一些C++的基本概念,为范磊的《零起点学通C++》,如下是一些笔记。数组

 

      内容:app

  delete p;只是删除指针p指向内存区,并非删除指针p,因此p仍是能够用的。删除空指针所指向内存是能够的。函数

  堆中的变量和对象时匿名的,没有名称,只能经过指针来访问。this

  在堆中建立对象时,在分配内存的同时会调用类的构造函数,在删除堆中对象时,会调用类的析构函数。spa

  为了不内存泄露,在删除一个指针后应该将其其值赋为0。指针

  常量指针是指针指向的内存区域地址不能改变,可是该内存地址里保存的值是能够改变的,好比int a; int * const p = &a;对象

  指向常量的指针表示指针指向的对象是不能被修改的,可是该指针能够被修改,即该指针能够指向另外一块目标内存地址。好比const int a = 0; const int *p = &a; 若是A是一个类,也能够为const A* p = new A;继承

  而指向常量的常指针表示指针自己不能被修改,其指向的内存地址内容也不能被修改。好比const int a = 0; const int * const p = &a;生命周期

  引用就是别名常量。

  堆中的地址是用指针来操做的,用不到别名。

  若是在main函数前面的其它函数的声明和定义是一块儿的,则代表这个函数是内联函数!所以当该函数较长时,应该将声明和定义分开。

  能够经过指针或引用来返回多个值,由于返回机制只能返回一个值,因此其它的返回值当作参数来传入,经过引用或指针。若是按值传递时,对象很大,则系统开销会很大(好比对象传入和返回,要建立2次临时对象,所以也会屡次调用构造函数和析构函数),此时,通常采用按地址传递或按引用传递。

  既然引用实现了指针的功能,并且使用起来更加方便,为何还要指针呢?

  这是由于指针能够为空,可是引用不能为空,指针能够被赋值,可是引用只能够被初始化,不能够被赋为另外一个对象的别名。若是你想使用一个变量来记录不一样对象的地址,那么就必须使用指针,另外指针也能够是多重的。

  指针能够指向堆中空间,引用不能指向堆中空间。但指针和引用能够一同使用,另外要注意引用的生命周期。

  对于引用而言,若是引用是一个临时变量,那么这个临时变量的生存周期不会小于这个引用的生存期。指针不具有这个特性。

  为了不内存泄露,咱们不能按值的方式返回一个堆中对象,而必须按地址或者别名的方式返回一个别名或者内存地址,这样就不会调用复制构造函数来建立一个该对象的副本了,而是直接将该对象的别名或者地址返回。

  为了不指针混淆,咱们必须对堆中的内存在哪一个函数中建立,就在哪一个函数中释放。

  若是函数名相同,函数参数的个数也相同,只是参数的类型不一样,则也能够是函数重载。

  若是函数有缺省值,则在调用时该参数能够不传入,这样至关于函数个数少了。

  默认参数其实也能够看作是一种函数重载,但默认参数的函数若是不加标注的话很容易被忽略,并且容易被有参数的同名函数覆盖。而一般的重载函数使用方便,易于理解。具备默认参数的重载的是参数的数值,而重载函数重载的是参数的类型。

  我能够对构造函数的函数头对常量和引用进行初始化,此时的初始化顺序是按照成员列表的顺序进行的,而不是按构造函数头赋值的顺序。而析构顺序刚好相反。

  通常状况下,编译器会自动为类生成一个默认的复制构造函数。

  清楚构造函数和new的结合,析构函数和delete的结合。

  构造函数是不能设置为私有的。

  默认的构造函数是浅层的构造函数,若是类中的成员变量有指针的话,就颇有可能出现内存泄露的错误,所以此时须要使用深层的构造函数。

  用已有对象来建立对象时,才会调用复制构造函数。若是复制符左侧是已有对象,右侧也是已有对象,则不会调用复制构造函数,而是调用一个赋值运算符函数。

  只要建立一个类,编译器就会自动添加4个函数:构造函数,析构函数,复制构造函数,赋值运算符函数,其中系统默认的复制构造函数和复制运算符都属于浅层拷贝。

  默认的自加剧载运算符为前置自加运算符。

  能够经过建立一个无名的临时对象来完成重载自加后的对象赋值操做。固然了,较好的方法是返回*this指针,这样就不须要创建一个临时对象了,不过它依旧会调用赋值运算符,为了不这种状况,能够将重载自加函数返回值类型设为返回对象的引用。

  重载后置自加运算符时,为了区分与前置自加的区别,须要添加一个毫无心义的参数,这个参数只是在编译器中使用到,在函数体中没用。

  在一条语句中自加运算符的执行顺序为从右向左,且不一样的编译器入栈的顺序不一样,好比说VC6.0中其入栈是要求该语句的表达式执行完后。所以a=1;cout<<a++<<++a;则分别输出的是2,2;

  ++的结合性为右结合,因此++++i合法,而i++++不合法,能够改成(i++)++;

  函数的按值返回时,会创建一个临时的对象,返回完后随后又被销毁。

  在符合隐式类型转换的状况下,能够将一个变量赋值给一个对象,可是不能反过来(除非本身重写重载函数)。

  重载类型转换运算符是没有返回值的,和构造函数,析构函数同样。

  只有派生类对象能够赋值给基类对象,反过来是不行的。另外,基类指针和引用能够指向派生类,反过来也是不行的。

  多重继承容许分别设置基类的派生权限。

  单一继承中构造与析构的顺序时,先构造的对象后析构。若是是多重继承,则构对象函数的顺序按照继承列表中的顺序来。

  多重继承中,若是多个基类中的函数名相同,则在子类对象调用该函数时会产生混淆,此时应该加入类做用域符。

  当咱们在子类中定义一个与基类相同的同名函数时,那么等于告诉编译器,用子类的函数覆盖掉基类的同名函数,同时将基类的重载函数给隐藏起来了,此时子类对象中不能再调用父类的对应的重载函数了。

  const对象只能调用const成员函数。

  若是一个派生类从多个基类派生,而这些基类又有一个共同的基类,那么在派生类中访问共同基类中的成员函数时会产生二义性,解决方法是须要指定类的做用域,或者将共同的基类设置为虚基类,由于虚基类不会产生二义性。

  一个虚函数被说明为虚函数,在派生类中覆盖了该函数,那么该函数也是个虚函数,不过你也能够在它前面添加关键字virtual,这样更容易理解。

  继承所体现出的不一样子类相同函数有不一样的表现,可是这个并不能体现类的多态性,由于类的多态性要求能够用基类指针来操做子类。

  将一个调用函数联接上被正确调用的函数,这一过程叫作函数联编,通常简称为联编,联编分为静态联编和动态联编2种。

  须要分清楚在编译时的静态联编,在运行时的静态联编,在编译时的动态联编,在运行时的动态联编这几种状况。

  假如咱们在虚函数中没有采用指针或引用,那么就没法实现动态联编。

  三种调用虚函数的方式,即按值调用,按指针调用和按引用调用,其中只有按值调用不能体现类的多态性,其它2种均可以。

  在虚函数中可使用成员名限定强行解除动态联编。

  若是基类中定义了虚函数,析构函数也应该说明为虚函数。这样对内存的回收会更准确些。基类是虚析构函数时,若是派生类被销毁,则首先是调用派生类的析构函数,而后才是基类的析构函数。

  数组一般比较大,因此为了节省内存,C++规定数组在程序只有一个本来,因为这个缘由,数组在函数中是不可能在创造一个副本的。C++为了追求程序的运行速度,不对数组进行越界检查。

  若是a表示的是数组指针,delete[] a,表示删除堆中的指针数组a,而delete a,表示删除堆中的指针数组第一个指针。

  用cin输入字符时,会把空格当作是字符串的结束字符,所以能够采用gets()函数。或者使用cin.get()函数,该函数有2个参数,第一个是数组,第二个是字符串的大小。

  在重载下标运算符函数时应该注意:1.因为函数的参数便是数组的下标,所以该函数只能带一个参数,不可带多个参数。2.因为下标运算符只限于本类的对象使用,所以不得将下标运算符函数重载为友元函数,且要求是非静态类的成员函数。

  因为malloc和free函数产生于C语言时代,所以不可用在c++的对象中,由于对象的产生要调用构造函数。

  dynamic_cast的做用是对不一样类之间的数据类型进行转换,它能够将一个基类的指针转换成一个派生类的指针。dynamic_cast属于RTTI(运行时信息),须要在工程设置中将其启动。在程序中应该少用RTTI.

  若是使用指向基类的指针来指向派生类,那么该指针不能直接调用派生类中多余的成员函数(能够经过强制类型转换),除非该函数在基类中声明成了虚函数。

  由抽象类派生的类须要为每个纯虚函数赋予具体功能。抽象类不能用来定义抽象类对象,可是却能够定义一个指向抽象类的指针。

  一个抽象基类仍然能够派生出抽象类,只要该类没有把纯虚函数所有覆盖掉。由于派生出的抽象类,若是其子类没有将它的纯虚函数所有覆盖掉,那么该子类也属于抽象类。

  在用单一继承就能够实现的状况下,不要使用多重继承。

  静态成员变量须要有定义和声明两个阶段。且定义必须在全局定义,静态成员在没有对象以前已经存在了。

  公有的静态成员函数在程序中全部的函数都可以访问它,即包括那些非类的成员函数。而私有静态变量只能被类的成员函数调用,但前提是你必须定义一个对象。

  静态成员函数和静态成员变量是同样的,它们不单属于一个对象,而是属于整个类。静态成员函数只能调用静态成员变量,不能调用普通的成员变量。

  虽然能够经过对象来访问静态成员函数,可是最好是用类限定符来访问它们。

  基类和派生类均可以共享静态成员。

  类中任何成员函数均可以访问静态成员,可是静态成员函数不能直接访问非静态成员,只能经过对象名访问该对象的非静态成员。由于静态成员函数是属于整个类的,没有特定指向某个对象的this指针。

  静态成员函数不能被说明为虚函数。

  函数名是指向函数的第一条指令的常量指针,这与数组名是指向数组中第一个元素的常量指针同样。

  函数指针应该将函数名和前面的指针给括起来。

  使用函数指针能够减少一些重复的代码,由于函数指针名能够看做是函数名的代号,咱们能够经过它来直接调用,函数指针常常会在条件或者判断语句里出现,以便于用户选择调用不一样名字但又返回值类型和参数类型彻底相同的函数。

  函数指针能够做为函数的参数传入。

  可使用typedef来简化函数指针的声明,后面以分号结束,注意这点和宏定义是不一样的,也能够在类中使用成员函数指针,或者成员函数指针数组。

  空格的ascii码为32,而空字符的ascii码为0.

  cout遇到空字符会中止输出,但与cin不一样的是,cout能够输出空格,制表符等空字符或者不可见字符。

  若是char型数组后面没有添加字符串结束符的话,这它不是一个字符串,而是一个数组。

  strlen返回的是字符串结束标志’\o’以前的字符串长度,而不是数组长度。sizeof返回的是数组的所占的字节长度。

  char字符串的比较只能用循环的方式进行(或者使用库函数strcmp函数),而string的比较能够直接用等号。

  不能够直接对char型字符串数组进行赋值操做,而只能使用strcpy函数,或者对数组每一个元素一个个的赋值。而string类的字符串能够直接用等号进行赋值。另外,string类中还有一个专门的赋值函数assign,这个函数可指定赋值字符串起点和长度。

  查看char型字符串的长度能够用strlen函数。string中用size成员函数实现该功能。固然了string类中的length函数也是同样的功能,二者的区别仅仅在size是为了兼容STL而出现的,而length是早起的string计算长度的版本。

  未被初始化的string对象是个空对象,除了字符串结束标志外,没有任何数据。

  在char中,strncat能够实现部分字符串的合并。在string中是append函数。同理,char中用strncpy来实现字符串的替换,在string中使用replace来实现该功能,且replace的重载函数中能够兼容char型字符串数组。

  char型字符串的拷贝用memmove, string中使用copy成员函数。

  string中用insert来插入,其string类是从下标为1开始数的。erase完成字符串的删除。

  char型字符串的查找使用函数strchr。而string类中使用find函数实现。该函数有不少变形的函数,好比find_first_not_of函数,表示找到第一个不相同的字符。同理还有find_first_of,find_last_of等函数。反向查找使用rfind()函数,可是它的返回值位置仍是从头开始的,并非从末尾开始的。

  string中用compare实现比较,它的c_str()返回一个指向char型的const指针。

char型字符串传参数到函数中时(能够经过指针或者字符串数组传入),能够不用传入字符串的长度,由于它有结束符,能够用来做为其结束的标志。

  C++中结构体与类惟一不一样的区别是,结构体的成员默认的是公有的,其它类有的,结构体也有,好比继承,多态等。

  为了使计算机执行减法,采用了补码的形式,由于引入了负号。

  派生类的析构函数会自动调用基类的析构函数。

  只要基类中的析构函数被说明为虚函数,那么派生类的析构函数不管说明与否,都天然是虚构函数。

  友元函数并非类的成员函数,而是类的外部函数,可是该外部函数中类的对象能够调用类的私有成员,而通常状况下,类的对象时不能调用类的私有成员的。

  常量对象只能调用可操做常量对象的成员函数(即参数括号后面带有const的成员函数),而不是常量对象的成员函数只能被很是量对象调用,所以常量成员函数和很是量成员函数也算是一种函数重载形式。常量对象的私有数据成员是不可以被修改的,除非在构造函数中第一次修改。且const成员函数中不能调用非const函数。

  友元类的做用不是相互的,须要单独设置。

  包含对象是将另外一个类的对象做为该类的成员,而嵌套类是在该类中定义了一种新类型,这个类型只能在该类中使用。因为嵌套类做为一种自定义的数据类型被封装在另外一个类中,所以可避免与其它类的名称冲突。

 

      参考资料:

  《零起点学通C++》,范磊。

相关文章
相关标签/搜索