C++ primer 阅读笔记
C++ primer阅读笔记
++val
和val=val+1
等效。tmp
指针后边加括号,返回的是它所指的对象。- 成员函数的调用方法:
对象.函数()
,引用.函数()
或指针->函数
.
称为点操作符,函数名后边必须加括号,括号里边是实参列表,可以为空,也可以是另一个对象。 - 无符号类型
unsigned
std::cout
中的::
是作用域操作符,一个命名空间后边接一个对象名。- 初始化分两种:直接初始化和复制初始化。
- 直接初始化:
int ival(1024);
- 复制初始化:
int ival=1024;
- 直接初始化:
- 定义如何进行初始化的成员函数称为构造函数,构造函数可以有多个,每个构造接受不同数目或者类型的参数。 此外,如果定义某个类的变量时没有提供初始化式,则使用默认构造函数。如果没有默认构造函数,则必须提供显式的初始化式。
- 对象可以用任意复杂的表达式(包括函数的返回值)来初始化:
double salary = 99.99, wage(salary + 0.01) ; |
- 变量一定要初始化。
- 变量的定义(definition)用于为变量分配存储空间,还可以为变量指定初始值。在一个程序中,变量有且只有一个定义。
- 声明(declaration)用于向程序表明变量的类型和名字。定义也是声明:当定义变量时我们声明了它的类型和名字。可以通过使用extern关键字声明变量名而不定义它。不定义变量的声明包括对象名、对象类型和对象类型前的关键字extern
extern int i; // 声明但没有定义
int i; //声明并且定义了
- 变量可以申明多次,但只能定义一次。
- 例外,只有当
extern
声明位于函数外部时,才可以含有初始化式。extern double pi = 3.14
( 声明并且定义了 ) - 变量必须且仅能定义一次,在使用变量前必须定义或声明变量。
- 多个文件共享一个变量,在一个文件中定义,其他文件中声明。
- 常量定义
const int zuff = 512;
- 因为常量在定义后就不能修改,所以定义时必须初始化。
- 非
const
变量默认为extern
。要使const
变量能够在其他的文件中访问,必须在定义它时显式地指定它为extern
int ival = 1024;
int &refval = ival;
- 引用必须用与该引用同类型的对象初始化。
- 引用与被引用指向同一地址
const
引用是指向const
对象的引用,如下:const int ival = 1024;
const int &refval = ival;const
对象不能有非const
引用,如Int &ref2 = ival
是错误的!const
引用可以初始化为不同类型的对象或者初始化为右值。如:int i = 42; const int &r = 42; const int &r2 = r + i;
上边的这两种初始化对于非const引用却是不合法的。typedef
用于给类型起别名,如typedef double wage
表示 wage 就是 double 类型的别名,可以用来定义对象- 类 通过构造函数初始化数据成员
- struct 也可以定义类
- 默认情况下,struct 的成员是 pubic,而 class 的成员是 private
- 头文件不能包含定义,只能有声明,但有三个例外:头文件可以定义类,值在编译时就已知的 const 对象和 inline 函数。
- argc 是程序的参数数量,包含程序名本身
- argv[] 指向命令行的每个字符
- vector 是类模板,
vector<int> ival;
类型放在尖括号中 - 双冒号(::)用法
- 表示“域操作符”
例:声明了一个类 A,类 A 里声明了一个成员函数void f(),但没有在类的声明里给出f的定义,那么在类外定义 f 时,就要写成void A::f(),表示这个 f()函数是类A的成员函数
- 表示“域操作符”
- c++ 中冒号(:)和双冒号(::)的用法 构造函数后边有一个冒号,那是初始化列表区
- 指针定义:
int a = 1; int *b = &a;
* 是解引用操作符,& 是取地址操作符。 - 指针本身是地址,* 加指针表示该存储在该地址的对象
- 指向 const 的指针,很明显,我们不能通过指针来修改这一数据,但我们可以改变指针所指对象啊。const double *ptr 这个特性可用作函数形参,防止在函数中修改这一变量。const double pi = 3.14; const double *ptr = π
- const 指针:
int err = 0; int *const cur = &err;
只能指向这个对象,不能指其他人。必须在定义时初始化 - 指向 const 对象的 const 指针,既不能指向它处,也不能修改值。
- 函数的形参,如果是普通变量时,是按值传递的,即把实参复制一遍给形参。当使用指针或引用时,即为按址传递,但这样可能不安全(实参有被篡改的风险),所以有了const引用(或指向const的指针)的形参,这样既能按址传递,又能保护实参不被修改。 意思就是,我把实参传过去,只是让它起一些作用,我并不希望修改实参。所以就用const引用。
- 使用 const 引用形参有一个好处,即传递给他的实参既可以是 const 类型也可以是非 const 类型。而非 const 引用形参,只能传递给他非 const 实参,字面值常量也不允许传递给他,产生右值的表达式也不能传递给他。
- 迭代器表示 vector 索引。相当于数组名加下标
- 对于多维数组,ia[3][4] 表示三行四列,ia[2] 表示最后一行
- 可以将 a[3][2] 看成是一个具有 3 个元素的一维数组,因此 a.size()=3
- 通过引用传递数组,
return_type function(int (&arr)[10]) { body }
- 返回引用的函数 在函数名前加 &,最前边加上 const 表示返回值不可被修改。即,函数返回值不能当做左值,不能被赋值。
- 函数不能仅通过返回类型不同来重载
- C/C++ 中 const 关键字详解
- 常成员函数:
类名::fun(形参) const
又名 const 成员函数,const 成员函数不能修改调用该函数的对象。 - C++ 不允许在常量对象上调用成员函数,除非成员函数本身也被声明为常量。
- 当存在同名同参数和返回值的常量函数和非常量函数时,具体调用哪个函数是根据调用对象是常量对像还是非常量对象来决定的。常量对象调用常量成员;非常量对象调用非常量的成员。
- 对于非引用形参,const 和非 const 不可以重载。而对于引用或指针形参,const 和非 const 可以重载。
对于指针,说的是指向 const 对象的指针,并不是说 const 指针。对于引用,就是 const 引用,即指向 const 的引用。举例:const 类型 &或*
- const 位于函数前中后,哪个可以重载? 后!常量函数和非常量函数可以重载 中,也可以,不过需要引用形参
- • const 在函数后面,保证函数不会修改调用对象。这是常量函数。
• const 在函数前面,用于当函数返回值是引用时,不能使用返回的引用来直接修改它指向的结构。
• const 在形数表中时,保证既能按引用传递,又不会改变实参原来的值。 - 带有默认实参的函数,调用它时,可以省略一个实参。重载的时候,这个默认参数可以不考虑,相当于这个参数不存在。
- 对于 const 引用形参的函数,它既可以用 const 实参来调用,也可以用非 const 实参来调用。但同时也存在非 const 形参的函数(即 const 形参和非const形参重载)时,非const实参优先调用非const形参的函数。
- 当形参以副本传递时,不能基于形参是否为 const 来实现来重载。就是说非引用形参
- 函数的形参可以是指向函数的指针。
- 类型转换
static_cast<int>(2.56)
将 2.56 转换成 int 型 - C 风格的强制类型转换(Type Cast)很简单,不管什么类型的转换统统是:
TYPE b = (TYPE)a;
- C++ 风格的类型转换
- 在类内部定义的成员函数,自动作为 inline 函数。
- 类外定义的函数,在前边加上 inline 就行,类内声明的时候,可以不加 inline。声明和定义,随便加一个 inline 就行。
- const 指针:始终指向某个对象 int *const cur = &err;
PS:指向 const 的指针: const int * abc = &var; - const 引用:指向 const 的引用 const int &refval = ival;
- 对于引用或指针形参,const 和非 const 可以重载。这里指的是是否指向 const 对象。
- const函数和非 const 函数也可以重载。
- 调用类的成员使用点操作符,对于指针,使用->操作符。
- 定义默认构造函数的时候,如果其中有些成员数据的类型自身有默认构造函数,可以不初始化它,这样调用这个数据的默认构造函数。
- 构造函数不能声明为 const,因为他的作用本来就是给新建的对象赋初值,而 const 成员函数不能修改调用它的对象。
- 默认构造函数可以在冒号之后初始化,也可以在函数体内初始化。
- 但是有些成员,必须在冒号后,即初始化列表中初始化。这些成员是:没有默认构造函数的类型的成员,以及 const 或引用类型的成员。
- 构造函数冒号之后,函数体之前,那些变量应该都已经分配内存了,所以引用必须确定引用的对象是谁,const 也必须确定,没有默认构造函数的类型,也必须初始化。那些可以默认初始化的类型,随便都行,比如 int 之类的。
- 构造函数初始化的顺序是按类中定义的顺序,不管你在初始化中怎样的顺序。
- 逗号操作符从左至右计算每个表达式的值,并返回最右边操作数的值。有什么意义呢?
- 在基类中定义 virtual 函数,表示这个函数希望在派生类中重新定义。那么为什么要在基类中出现呢?基类不定义,派生类定义,这样不行吗?用于多态啊
- 基类希望派生类继承的函数不能定义为虚函数。
- 通过基类的引用(或指针)调用虚函数时,发生动态绑定。基类的引用既可以指向基类对象,也可以指向派生类对象,动态绑定表示运行时,被调用的函数根据引用指向的对象的实际类型来决定。
- 除了构造函数之外,任意非 static 成员函数都可以是虚函数。
- private 成员只能由基类的成员和友元访问。派生类对基类 的public和private成员的访问权限同其他代码一样,并不是继承者就可以随意访问,它也无法使用基类的private成员。但有些成员需要派生类访问,所以有了protected。
- protected 相当于给了派生类特权,可以访问基类的某些成员。
- 派生类只能通过派生类对象访问基类的 protected 成员,不能访问基类对象的 protected 成员。
- 基类提供给派生类的接口包括protected和public
- 派生 class classname:access_label base_class 可以指定多个基类.
- 派生类中虚函数的声明必须与基类中的定义方式完全一致。但有一个例外,返回对基类的引用的虚函数,派生类中的对应函数既可以返回对派生类的引用,也可以返回对基类的引用。
- 派生类定义虚函数时,可以加 virtual,也可以不加。虚函数不管继承多少次,永远是虚函数。
- 因为每个派生类对象都包含基类部分,所以可将基类类型的引用绑定到派生类对象的基类部分,也可以用指向基类的指针指向派生类对象。
- 任何可以在基类对象上执行的操作也可以通过派生类对象使用。
- 如果调用非虚函数,则无论实际对象是什么类型,都执行基类类型所定义的函数;虚函数则根据对象类型来判断。
- 使用 class 定义派生类默认具有 private 继承,使用 struct 定义派生类默认具有 public 继承。
- 友元可以访问类的 private 和 protected 成员。友元关系不能继承,基类的友元对派生类来说就是普通人一样。
- 如果基类和派生类都需要访问另一个类,则那个类必须将访问权限授予 基类和每一个派生类。
- static 成员,相当于整个类的公有变量。对于他的所有派生类也一样,基类和派生类共享 static 成员。
- 因为派生类对象也是基类对象,所以存在从派生类引用到基类引用的自动转换,即,可以将派生类对象的引用转换为基类子对象的引用,对指针也类似。
- 但是,没有从基类引用到派生类引用的转换。
- 虽然一般可以使用派生类的对象对基类对象进行初始化或赋值,但,没有从派生类对象到基类对象的直接转换。只能通过引用或指针。
- 当一个函数的形参是基类引用时,可以将派生类对象当做实参,这样的话,形参引用直接绑定到派生类对象上。对象未被复制。
- 当一个函数的形参是基类对象时,可以将派生类对象当做实参,这样的话,派生类对象的基类部分复制到形参。
- 用派生类对象对基类对象进行初始化或赋值时,实际调用的是基类的复制构造函数和复制操作符,只是这些函数本应该传入一个基类对象,实际上传入的是派生类对象。
- 用派生类对象调用基类的复制构造函数或赋值操作符时,将发生下列步骤:
- 将派生类对象转换为基类引用,这仅仅意味着将一个基类引用绑定到派生类对象。
- 将该引用作为实参传给复制构造函数或赋值操作符。
- 那些操作符使用派生类的基类部分分别对调用构造函数或赋值的基类对象的成员进行初始化或赋值。
- 一旦操作符执行完毕,对象即为基类对象。它包含派生类的基类部分的副本,但实参的派生类部分被忽略。
- 当构造、复制、赋值和撤销派生类对象时,也会构造、复制、赋值和撤销这些基类子对象。
- 某些类需要只希望派生类使用的特殊构造函数,这样的构造函数应该定义为 protected。
- 派生类的构造函数受继承关系的影响,每个派生类构造函数除了初始化自己的数据成员之外,还要初始化基类。基类部分可以由默认构造函数初始化。
- 内置类型,无法默认初始化。
- 如果派生类构造函数没有定义基类成员,则自动调用基类默认构造函数,并且是先调用基类构造函数,然后运行派生类构造函数的初始化列表,最后再运行函数体。
- 也可以在派生类构造函数中显式指定基类的构造函数。
- 在基类构造函数或析构函数中,将派生类对象当做基类对象对待。这会影响动态绑定。
- arugument 实参 parameter 形参
- 在普通的非 const 成员函数中,this 的类型是一个指向类类型的 const 指针。可以改变this 所指向的值,但不能改变 this 所保存的地址。
在 const 成员函数中,this 的类型是一个指向 const 类类型对象的 const 指针。既不能改变 this 所指向的对象,也不能改变 this 所保存的地址。
AAA