"); //-->
第五章 语句
P154-P178
5.1 简单语句
(1)空语句
; // 空语句
(2)复合语句
复合语句是指用花括号括起来的(可能为空的)语句和声明的序列,复合语句也被称作块(block)。
{}
5.2 语句作用域
定义在控制结构当中的变量只在相应语句的内部可见,一旦语句结束,变量就超出其作用范围。
5.3 条件语句
(1)if 语句
(2)switch 语句
case关键字和它对应的值一起被称为case标签。
case标签必须是整形常量表达式。
如果某个case标签匹配成功,将从该标签开始往后顺序执行所有case分支,除非程序显示的中断了这一过程。
dedault 标签:如果没有任何一个case标签能匹配上switch表达式的值,程序将执行紧跟在default标签后面的语句。
5.4 迭代语句
(1)while 语句
while (condition) statement
(2)传统 for 语句
for (initializar; condition; expression) statement
for 语句中定义的对象只在for循环体内可见。
(3)范围 for 语句
for (declaration : expression) statement
(4)do while 语句
do statement while (condition)
5.5 跳转语句
break
break只能出现在迭代语句或者switch语句内部。仅限于终止离它最近的语句,然后从这些语句之后的第一条语句开始执行。
continue
continue语句终止最近的循环中的当前迭代并立即开始下一次迭代。
goto
goto的作用是从goto语句无条件跳转到同一函数内的另一条语句。
容易造成控制流混乱,应禁止使用。
return
5.6 try语句块和异常处理
C++中异常处理包括:throw表达式、try语句块。
try和catch,将一段可能抛出异常的语句序列括在花括号里构成try语句块。catch子句负责处理代码抛出的异常。
throw表达式语句,终止函数的执行。抛出一个异常,并把控制权转移到能处理该异常的最近的catch字句。
第六章 函数
P182-P225
6.1 函数基础
(1)形参和实参:
实参的类型必须与对应的形参类型匹配。
函数的调用规定实参数量应与形参数量一致。
(2)局部对象
形参和参数体内部定义的变量统称为局部变量,它们对函数而言是"局部"的,仅在函数的作用域内可见,同时局部变量还会隐藏外层作用域中同名的其他变量。
自动对象:只存在于块执行期间的对象。
局部静态对象:在程序的执行路径第一次经过对象定义语句时候进行初始化,并且直到程序终止才会被销毁。
size_t count_calls() { static size_t ctr = 0; return ++ctr; }
(3)函数声明
函数的三要素:(返回类型、函数名、形参类型)。
函数可被声明多次,但只能被定义一次。
(4)分离式编译
分离式编译允许把程序分割到几个文件中去,每个文件独立编译。
编译->链接
6.2 参数传递
当形参是引用类型,这时它对应的实参被引用传递或者函数被传引用调用。
当实参被拷贝给形参,这样的实参被值传递或者函数被传值调用。
(1)传值参数
(2)被引用传参
(3)const形参和实参
(4)数组形参
为函数传递一个数组时,实际上传递的是指向数组首元素的指针。
void print(const int*); void pring(const int[]); void print(const int[10]); // 以上三个函数等价
数组引用实参:f(int (&arr)[10])
int *matrix[10]; // 10个指针构成的数组 int (*matrix)[10]; // 指向含有10个整数的数组的指针
(5)含有可变形参的数组
initializer_list
for err_msg(initializer_list<string> li)
6.3 返回类型和return语句
2种:无返回值函数和右返回值函数。
return; return expression;
函数完成后,它所占用的存储空间也会随着被释放掉。
::: warning
返回局部对象的引用是错误的;返回局部对象的指针也是错误的。
:::
6.4 函数重载
重载函数:同一作用域内的几个函数名字相同但形参列表不通,我们称之为重载函数。(overloaded)。
不允许2个函数除了返回类型外其他所有的要素都相同。
重载与作用域
如果在内存作用域中声明名字,它将隐藏外层作用域中声明的同名实体。
6.5 特殊用途语言特性
(1)默认实参
函数调用时,实参按其位置解析,默认实参负责填补函数调用缺少的尾部实参。
typedef string::size_type sz; string screen(sz ht = 24, sz wid = 80, char background = ' ');
::: tip
当设计含有默认实参的函数时,需要合理设置形参的顺序。一旦某个形参被赋予了默认值,它后面的所有形参都必须有默认值。
:::
(2)内联函数
使用关键词inline来声明内联函数。
内联用于优化规模较小,流程直接,频繁调用的函数。
(3)constexpr函数
constexpr函数是指能用于常量表达式的函数。
6.6 函数匹配
Step1:确定候选函数和可选函数。
Step2:寻找最佳匹配。
6.7 函数指针
函数指针指向的是函数而非对象。
void useBigger (const string &s1, const string &s2, bool pf(const string &, const string &)); 等价于 void useBigger (const string &s1, const string &s2, bool (*pf)(const string &, const string &));
第七章 类
P228-P273
类的基本思想是数据抽象和封装。
抽象是一种依赖于接口和实现分离的编程技术。
封装实现了类的接口和实现的分离。
7.1 定义抽象数据类型
(1)this
任何对类成员的直接访问都被看作this的隐式引用。
std::string isbn() const {return bookNo;}
等价于
std::string isbn() const {return this->bookNo;}
(2)在类的外部定义成员函数
类外部定义的成员的名字必须包含它所属的类名。
double Sales_data::avg_price() const { if (units_sol) return revenue/units_sols; else return 0; }
(3)构造函数
定义:类通过一个或几个特殊的成员函数来控制其对象的初始化过程,这些函数叫做构造函数。
构造函数没有返回类型;
构造函数的名字和类名相同。
类通过一个特殊的构造函数来控制默认初始化过程,这个函数叫做默认构造函数。
编译器创建的构造函数被称为合成的默认构造函数。
::: tip
只有当类没有声明任何构造函数的时,编译器才会自动的生成默认构造函数。
一旦我们定义了一些其他的构造函数,除非我们再定义一个默认的构造函数,否则类将没有默认构造函数
:::
7.2 访问控制与封装
(1)访问控制
说明符 用途
public 使用public定义的成员,在整个程序内可被访问,public成员定义类的接口。
private 使用private定义的成员可以被类的成员函数访问,但是不能被使用该类的代码访问,private部分封装了类的实现细节。
(2)友元
类可以允许其他类或者函数访问它的非公有成员,方法是令其他类或者函数成为它的友元。
以friend关键字标识。
友元不是类的成员,不受访问控制级别的约束。
::: tip
友元的声明仅仅制定了访问的权限,而非通常意义的函数声明。必须在友元之外再专门对函数进行一次声明。
:::
// Sales_data.h class Sales_data { friend Sales_data add(const Sales_data&, const Sales_data&); friend std::ostream &print(std::ostream&, const Sales_data&); friend std::istream &read(std::istream&, Sales_data&); } // nonmember Sales_data interface functions Sales_data add(const Sales_data&, const Sales_data&); std::ostream &print(std::ostream&, const Sales_data&); std::istream &read(std::istream&, Sales_data&); //Sales_data.cpp Sales_data add(const Sales_data &lhs, const Sales_data &rhs) { Sales_data sum = lhs; // copy data members from lhs into sum sum.combine(rhs); // add data members from rhs into sum return sum; } // transactions contain ISBN, number of copies sold, and sales price istream& read(istream &is, Sales_data &item) { double price = 0; is >> item.bookNo >> item.units_sold >> price; item.revenue = price * item.units_sold; return is; } ostream& print(ostream &os, const Sales_data &item) { os << item.isbn() << " " << item.units_sold << " " << item.revenue << " " << item.avg_price(); return os; }
7.3 类的其他特性
(1)重载成员变量
Screen myScrren; char ch = myScreen.get(); ch = myScreen.get(0,0);
(2)类数据成员的初始化
类内初始值必须使用=或者{}的初始化形式。
class Window_mgr{ private: std::vector<Screen> screens{Screen(24, 80, ' ')}; }
(3)基于const的重载
class Screen { public: // display overloaded on whether the object is const or not Screen &display(std::ostream &os) { do_display(os); return *this; } const Screen &display(std::ostream &os) const { do_display(os); return *this; } }
当某个对象调用display的时候,该对象是否是const决定了应该调用display的哪个版本。
(3)类类型
对于一个类来说,在我们创建他的对象之前该类必须被定义过,而不能仅被声明。
(4)友元
友元类
如果一个类指定了友元类,则友元类的成员函数可以访问此类包括非公有成员在内的所有成员。
class Screen { // Window_mgr的成员可以访问Screen类的私有部分 friend class Window_mgr; }
令成员函数作为友元
class Screen { // Window_mgr::clear必须在Screen类之前被声明 friend void Window_mgr::clear(ScreenIndex); }
7.4 类的作用域
一个类就是一个作用域。
7.5 构造函数再探
(1)构造函数的初始值有时必不可少
::: tip
如果成员是const、引用,或者属于某种未提供默认构造函数的类类型化。我们必须通过构造函数初始值列表为这些成员提供初值。
:::
class ConstRef{ public: ConstRef (int i); private: int i; const int ci; int &ri; }; ConstRef:ConstRef(int ii) : i(ii), ci(ii), ri(i){ }
(2)成员初始化的顺序
成员初始化的顺序与它们在类定义中出现 的顺序一致。P259
(3)委托构造函数
使用它所述类的其他构造函数执行它自己的初始化过程。
(4)如果去抑制构造函数定义的隐式转换?
在类内声明构造函数的时候使用explicit关键字。
7.6 类的静态成员
(1)声明静态成员
在成员的声明之前加上关键词static。
类的静态成员存在于任何对象之外,对象中不包含任何与静态成员有关的数据。
(2)使用类的静态成员
double r; r = Account::rate();
小结
类有两项基本能力:
一是数据数据抽象,即定义数据成员和函数成员的能力;
二是封装,即保护类的成员不被随意访问的能力。
*博客内容为网友个人发布,仅代表博主个人观点,如有侵权请联系工作人员删除。