4、C++ Primer 4th 笔记,基本语言相关的概念[3]

简介: 1、case 标号必须是整形常量表达式。 对于switch结构,只能在它的最后一个case标号或default标号后面定义变量;制定这个规则主要是为了避免代码跳过变量的定义和初始化的情况。可以为某个特殊的case定义变量通过块语句。

1case 标号必须是整形常量表达式。

对于switch结构,只能在它的最后一个case标号或default标号后面定义变量;制定这个规则主要是为了避免代码跳过变量的定义和初始化的情况。可以为某个特殊的case定义变量通过块语句。

2、异常类型[2]

    标准库异常类定义在四个头文件中:

1exception 头文件定义了最常见的异常类,它的类名是 exception。这个类只通知异常的产生,但不会提供更多的信息。

2stdexcept 头文件定义了几种常见的异常类,这些类型在表1中列出。

3new 头文件定义了 bad_alloc 异常类型,提供因无法分配内存而由 new抛出的异常。

4type_info 头文件定义了 bad_cast 异常类型。

1

exception

最常见的问题。

runtime_error

运行时错误:仅在运行时才能检测到问题

range_error

运行时错误:生成的结果超出了有意义的值域范围

overflow_error

运行时错误:计算上溢

underflow_error

运行时错误:计算下溢

logic_error

逻辑错误:可在运行前检测到问题

domain_error

逻辑错误:参数的结果值不存在

invalid_argument

逻辑错误:不合适的参数

length_error

逻辑错误:试图生成一个超出该类型最大长度的对象

out_of_range

逻辑错误:使用一个超出有效范围的值

 

3、使用预处理器进行调试

1)默认,NDEGUG未定义。

#ifndef NDEBUG

cerr << "starting main" << endl;

#endif

    预处理器还定义了其余四种在调试时非常有用的常量:

__FILE__ 文件名

__LINE__ 当前行号

__TIME__ 文件被编译的时间

__DATE__ 文件被编译的日期

__FUNCTION__ 函数名

2assert(expr) //cassert

只要NDEGUG未定义,assert就求解。

4、语法上块就是单语句。

5、函数不能返回另外一个函数或者内置数组类型,但可以返回指向函数的指针,或指向数组元素的指针的指针

6、可以将指向const对象的指针初始化为指向非const对象,反之不成立

应该将不需要修改的引用形参定义为const引用。普通的非const引用形参在使用时不太灵活;这样的形参既不能用const对象初始化,也不能用字面值或产生右值的表达式实参初始化。

如下示例

#include "iostream"
#include "string"
using namespace std;

string::size_type find_char(string &s, char c)
{
	string::size_type i = 0;
	while(i != s.size() && s[i] != c)
		++i;
	return i;
}

int main()
{
    if(find_char("hello world", 'o'))
		cout << "Yes";
	return 1;
}

应当把string &s写成const string &s

7、指向指针的引用

void ptrswap(int *&v1){}

8C++程序员倾向于通过传递指向容器中需要处理的元素的迭代器来传递容器。

示例

// pass iterators to the first and one past the last element to print
void print(vector<int>::const_iterator beg,
vector<int>::const_iterator end)
{
while (beg != end) {
cout << *beg++;
if (beg != end) cout << " "; // no space after last element
}
cout << endl;
}

9、数组的两个特殊性质:

一是不能复制数组;二是使用数组名字时,数组名会自动转化为指向其第一个元素的指针。

当编译器检查数组形参关联的实参时,它只会检查实参是不是指针、指针的类型和数组元素的类型时是否匹配,而不会检查数组的长度。

一般来说,非引用类型的形参会初始化为其相应实参的副本。

10、多维数组就是数组的数组。

11、传递给函数的数组的处理

1)在数组本身放置一个标记来检测数组的结束。C 风格字符串就是采用这种方法

的一个例子,它是一种字符数组,并且以空字符 null 作为结束的标记。处理 C

风格字符串的程序就是使用这个标记停止数组元素的处理。

2)第二种方法是传递指向数组第一个和最后一个元素的下一个位置的指针。如同前面的例子所示。

3)第三种方法是将第二个形参定义为表示数组的大小。

12、函数的返回值用于初始化在调用函数处创建的临时对象。在求解表达式时,

如果需要一个地方储存其运算结果,编译器会创建一个没有命名的对象,这就是

临时对象。

千万不要返回局部对象的引用或指针。

13、默认实参

如果有一个形参具有默认实参,则它后面所有的形参都必须有默认实参。默认实参只能用来替换函数调用缺少的尾部实参。在一个文件中,只能为一个形参指定默认实参一次。通常在函数声明中指定,并把该声明放在合适的头文件中。

如果在函数定义的形参表中提供默认实参,那么只有在包含该函数定义的源文件中调用该函数时,默认实参才是有效的。

14、作用域和生存期

名字的作用域指知道该名字的程序文本区。对象的生存期是在程序执行过程中对象生存的时间。

示例代码

size_t count_calls()
{
static size_t ctr = 0; // value will persist across calls
return ++ctr;
}
int main()
{
for (size_t i = 0; i != 10; ++i)
cout << count_calls() << endl;
return 0;

输出1,2,3...

15、重载

函数不能仅仅基于不同的返回类型而实现重载。

值得注意的是,形参与 const 形参的等价性仅适用于非引用形参。有 const 引用形参的函数与有非 const 引用形参的函数是不同的。类似地,如果函数带有

指向 const 类型的指针形参,则与带有指向相同类型的非 const 对象的指针形参的函数不相同。

在函数中局部声明的名字将屏蔽在全局作用域内声明的同名名字。这个关于变量名字的性质对于函数名同样成立。同样,作用域规则也适用于重载函数名。如果局部地声明一个函数,则该函数将屏蔽而不是重载在外层作用域中声明的同名函数。

同名查找发生在类型检查之前。

可基于函数的引用形参是指向 const 对象还是指向非 const 对象,实现函数重载。不能基于指针本身是否为const 来实现函数的重载。

16、常量成员函数不能修改所操作的对象的数据成员。

17、函数指针

1)在引用函数名但又没有调用该函数时,函数名将被自动解释为指向函数的指

针。假设有函数:

// compares lengths of two strings

bool lengthCompare(const string &, const string &);

    除了用作函数调用的左操作数以外,对 lengthCompare 的任何使用都被解

释为如下类型的指针:

bool (*)(const string &, const string &);

2)可使用函数名对函数指针做初始化或赋值。函数指针只能通过同类型的函数或函数指针或 0 值常量表达式进行初始化或赋值。将函数指针初始化为 0,表示该指针不指向任何函数。指向不同函数类型的指针之间不存在转换。

3)如下一下定义:

int (*ff(int))(int*, int);//ff声明为一个函数,它带有一个int型的形参。该函数返回int (*)(int*, int);

允许将形参定义为函数类型,但函数的返回类型则必须是指向函数的指针,不能是函数。

4)函数指针形参

按两种形式编写:

// third parameter is a function type and is automatically treated as a pointer to function
void useBigger(const string &, const string &,bool(const string &, const string &));
// equivalent declaration: explicitly define the parameter as a pointer to function
void useBigger(const string &, const string &,bool (*)(const string &, const string &));

5)指向重载函数的指针

指针的类型必须与重载函数的一个版本精确匹配。

extern void ff(vector<double>);
extern void ff(unsigned int);
// which function does pf1 refer to?
void (*pf1)(unsigned int) = &ff; // ff(unsigned)

18、静态局部对象和全局变量在程序开始执行时创建,main结束时撤消。默认初始化值为0,而其它局部变量则默认初始化未定义。

19this指针

    成员函数的隐式形参。this指针指向调用该函数的对象,是指向类类型的指针。在 const 成员函数中,该指针也指向 const 对象。

参考:

[1] http://blog.163.com/zhoumhan_0351/blog/static/3995422720104881216900/

[2] http://blog.163.com/zhoumhan_0351/blog/static/39954227201048103141504/

目录
相关文章
|
1月前
|
编译器 C++
C++语言预处理器学习应用案例
【4月更文挑战第8天】C++预处理器包括条件编译、宏定义和文件包含等功能。例如,条件编译用于根据平台选择不同代码实现,宏定义可简化常量和变量名,文件包含则用于整合多个源文件。示例中展示了如何使用`#ifdef`等指令进行条件编译,当`DEBUG`宏定义时,`PRINT_LOG`会打印调试信息,否则不执行。
14 1
|
2月前
|
Java 编译器 C++
C++入门指南:类和对象总结笔记(下)
C++入门指南:类和对象总结笔记(下)
30 0
|
13天前
|
Linux 程序员 图形学
C++语言在现代软件开发中的应用与实践
C++语言在现代软件开发中的应用与实践
20 2
|
13天前
|
存储 程序员 C语言
深入理解C++:从语言特性到实践应用
深入理解C++:从语言特性到实践应用
23 3
|
13天前
|
存储 算法 安全
C++语言深度探索:从基础到实践
C++语言深度探索:从基础到实践
13 2
|
14天前
|
安全 Java 程序员
【C++笔记】从零开始认识继承
在编程中,继承是C++的核心特性,它允许类复用和扩展已有功能。继承自一个基类的派生类可以拥有基类的属性和方法,同时添加自己的特性。继承的起源是为了解决代码重复,提高模块化和可维护性。继承关系中的类形成层次结构,基类定义共性,派生类则根据需求添加特有功能。在继承时,需要注意成员函数的隐藏、作用域以及默认成员函数(的处理。此外,继承不支持友元关系的继承,静态成员在整个继承体系中是唯一的。虽然多继承和菱形继承可以提供复杂的设计,但它们可能导致二义性、数据冗余和性能问题,因此在实际编程中应谨慎使用。
17 1
【C++笔记】从零开始认识继承
|
19天前
|
存储 人工智能 编译器
【重学C++】【指针】一文看透:指针中容易混淆的四个概念、算数运算以及使用场景中容易忽视的细节
【重学C++】【指针】一文看透:指针中容易混淆的四个概念、算数运算以及使用场景中容易忽视的细节
29 1
|
20天前
|
Linux C++
c++的学习之路:24、 二叉搜索树概念
c++的学习之路:24、 二叉搜索树概念
31 1
|
25天前
|
机器学习/深度学习 人工智能 大数据
开发语言漫谈-C++
C++最初的名字为“带类的C”
|
25天前
|
缓存 编译器 API
NumPy与其他语言(如C/C++)的接口实践
【4月更文挑战第17天】本文介绍了NumPy与C/C++的接口实践,包括Python与C/C++交互基础、NumPy的C API和Cython的使用。通过案例展示了如何将C++函数与NumPy数组结合,强调了内存管理、类型匹配、错误处理和性能优化的最佳实践。掌握这些技能对于跨语言交互和集成至关重要。