c++--语言基础知识 1.constconst修饰变量表示变量不可修改这样的变量称为常量。后续统一将没有const修饰的变量叫变量const修饰的变量叫常量。1.1.修饰指针时注意区分限定的是指针还是指针指向的对象。int a; const int * p1 a;// const修饰p1指向对象此时允许修改p1不允许修改*p1。p1合法*p11非法。 int * const p2 a;// const修改p2自身此时不允许修改p2允许修改*p2。p2不合法*p21合法。1.2.顶层const底层const1.2.1.区分int a; const int *p1 a;// 这里我们定义一个变量p1。此时p1是变量。p1指向的对象是常量。 int * const p2 a;// 这里我们定义一个变量p2。此时p1是常量。p1指向的对象是变量。 const int q1 a;// 这里我们定义一个引用q1注意引用不是变量只是给引用对象起来一个别名。 此时q1是变量a的引用。不允许通过q1修改a的值。 int const q2 a;// 用const修饰引用自身没有意义。引用自身本来就是初始化绑定变量后不可变更绑定的。允许通过q2修改a的值。(1).顶层const修饰变量自身。如上述修饰p2的const。(2).底层const修饰变量/引用指向对象。如上述修饰p1q1的const。1.2.2.作用(1).顶层const变量执行拷贝构造赋值时若左边变量用顶层const修饰右边可以是同类型变量也可是同类型常量。若左边变量无顶层const修饰右边依然可以是同类型变量也可是同类型常量。class A { private: int m_i; }; int main() { A a; const A ca a; // ok const A cb ca; // ok A b ca; // ok a b;// ok a ca;// ok }从理解的角度拷贝或赋值时左边和右边是两个独立的变量。右边的变量只负责提供内容。顶级const修饰与否对变量内容无影响。(2).底层const指针类型变量执行拷贝构造赋值时若左边变量用底层const修饰右边必须是同类型的变量或常量是否被底层const修饰均可以。若左边变量无底层const修饰右边必须是同类型的变量或常量。不可被底层const修饰。class A { private: int m_i; }; int main() { A a; const A ca a; A* p1 a;// ok A* p2 ca;// err const A *cp1 ca;// ok const A* cp2 a;// ok p1 a;// ok p1 ca;// err cp1 a;// ok cp1 ca;//ok }引用执行初始化时左边被底层const修饰时右边可以是所引用类型的变量或常量。左边没有底层const修饰时右边只能是所引用类型的变量。class A { private: int m_i; }; int main() { A a; const A ca a; A aa1 a;// ok A aa2 ca;// err const A bb1 a;// ok const A bb2 ca;// ok }1.3.可见性c语言中被const修饰的全局变量只在所在文件内可见。额外添加extern修饰后变为全局可见。c/c语言中被static修饰的全局变量只在所在文件内可见。c/c语言中无conststatic修饰的全局变量全局可见。2.强制类型转换2.1.新式(1).static_cast会导致精度损失的数值转换void*到其他指针类型的转换。(2).const_cast用于为右边对象去掉或加上底层const属性。(3).reinterpret_cast非void*指针类型间转换。(4).dynamic_cast用于基类指针基类引用转换为派生类指针派生类引用。2.2.旧式旧式(TargetType)xx;3.重载与作用域同一个作用域内各个同名函数间有重载关系名字查找先从内层作用域依次往外层作用域查找在当前作用域内找到名字后停止继续查找。进入匹配阶段。一个实例#include iostream using namespace std; struct Base{ void f(double i){cout Base: i endl;} }; struct Derived : public Base{ using Base::f; void f(int i){cout Derived: i endl;} }; int main(){ Base b; b.f(4.5); Derived d; d.f(4.5); d.f(10); return 0; }上述执行d.f(4.5)匹配到了基类版本。这是因为我们通过在派生类里执行using Base::f;使得基类的符号f参与到从派生类作用域开始的名字查找过程。这样执行d.f(4.5)时通过在派生类作用域的名字查找找到两个为f的名字。接下来通过类型匹配绝对采用哪个f。这样由于基类的f可以精确匹配所以最终选择基类版本。#include iostream using namespace std; struct Base{ void f(double i){cout Base: i endl;} }; struct Derived : public Base{ //using Base::f; void f(int i){cout Derived: i endl;} }; int main(){ Base b; b.f(4.5); Derived d; d.f(4.5); d.f(10); return 0; }上述执行d.f(4.5)匹配到了派生类版本。因为执行d.f(4.5)时通过在派生类作用域的名字查找只能找到一个为f的名字。所以最终选择派生类版本。针对派生类执行调用时首先在派生类搜索函数名称若搜索到进入匹配阶段若搜索不到继续到基类搜索函数名称若搜索到进入匹配阶段若搜索不到报错。这里额外注意两点(1).名字查找和类型匹配发生在编译阶段。(2).using改变的是关联符号在作用域内的可见性。上述using使得Base::f在派生类作用域可见。默认下Base::f在基类作用域可见。4.默认实参。用作默认实参的名字在函数声明所在的作用域内被解析而这些名字的求值过程发生在函数调用时。内联函数在编译时展开展开函数需要定义。5.函数匹配5.1.确定候选函数和可行函数候选函数(1).其声明在调用点可见。(2).与被调用函数同名。可行函数(1).形参数量与实参数量相等。(2).每个实参类型和对应形参类型相同或可转换成形参类型。5.2.寻找最佳匹配(1).该函数的每个实参的匹配都不劣与其他可行函数需要的匹配(2).至少有一个实参的匹配优于其他函数提供的匹配。5.3.实参类型转换等级(1).精确匹配a.类型相同。b.数组或函数转成指针。c.去掉或添加顶层const。(2).非底层const实参转成底层const形参。(3).类型提升派生类指针转成基类指针。(4).类类型转换同一等级不再区分优劣。