《C++ Primer Plus》学习笔记3

《C++ Primer Plus》学习笔记3

第8章 函数探幽

===================================================================================================================

1、C++内联函数和常规函数

1)常规函数调用使程序跳到另一个地址(函数地址),并在函数结束时返回。具体过程是执行到函数调用指令时,程序将在函数调用后立即储存指令的内存地址,并将函数参数赋值到堆栈,跳到标记函数起点的内存单元,执行函数代码,之后跳回到地址被保存的指令处。

2)内联函数无需跳到另一个位置处执行代码,所以运行速度比较快,但是代价是占用更多的内存。用相应的代码替换函数的调用,只有在函数很短时才能采用内联方式。

要使用内联函数我要必须要采用下面措施之一:

①在函数声明前加上关键字inline

②在函数定义前加上关键字inline

通常我们都直接省略原型,直接放在最前面

inline double square(double x)
{
    return x * x;
}

3)内联和宏

inline是c++的新增的特性,C语言中通过使用预处理语句#define来提供宏,这个其实是内联代码的原始实现,这里需要注意宏并不是通过传递参数来实现的,而是通过文本替换来实现的。宏不能按值传递

#define SQUARE (x) X*X
改进:#define SQUARE (x) (X*X)

所以我们想到以后用宏的时候要想到装换为内联函数。

2、引用

1)引用不同于指针,出了写法不一样,还有其他的差别,例如引用必须在声明引用时将其初始化,而不能像指针那样,先声明再复赋值

int rats = 101;
int & rodents = rates;
int * prats = &rates;

下面错误写法:

int rat;
int & rodent;
rodent = rat;

3、按值、按引用、按指针传递的比较:

//按引用传递
void swapr(int &a, int  &b)
{
    int temp;

    temp = a;
    a = b;
    b = temp;
}
//按指针传递
void swapp(int *p, int *q)
{
    int temp;

    temp = *p;
    *p = *q;
    *q = temp;
}
//按值传递
void swapv(int a,int b)
{
    int temp;
    temp = a;
    a = b;
    b = temp;
}

比较按引用传递和按值传递

①声明函数的方式不一样

②在引用传递中,因为我们a,b就是别名,所以变换a和b的值,也就相当于变调用函数的值,但是对于值传递中,变量a,b是属于复制了调用函数的变量,所以变换a,b的值并不会改变原调用函数的值,所以这种传送方式不行。

比较按引用传递和按指针传递

①声明方式不一样

②指针传递方式中需要在函数使用p,q的整个过程中使用解除引用操作符*

swapr(wallet1, wallet2); 即将形参a和b分别初始化为wallet1和wallet2;

4、临时变量、引用参数、const

下面三种情况要尽可能使用const

①使用const可以避免无意中修改数据的编程错误

②使用const是函数能够处理const和非const实参,否则将只能接受非const数据

③使用const引用使函数能够正确生成并使用临时变量,所以应该尽可能将引用形参声明为const.

5、使用引用参数的主要原因有两个:

1)程序员能够修改调用函数中的数据对象

2)通过传递引用而不是整个数据对象,可以提高程序的运行速度。

6、引用参数实际上是基于指针的代码的另一个接口

对于使用传递的值而不作修改的函数:

1)如果数据对象很小,如内置数据的类型或者小型结构,则按值传递

2)如果数据对象是数组,则使用指针,因为这是唯一的选择,并且将指针声明为指向const的指针。

3)如果数据对象是较大的结构,则使用const指针或const引用,以提高程序的效率,这样可以节省复制结构所需要的时间和空间。

4)如果数据对象是类对象,则使用const引用。传递类对象的标准方式是按引用传递

7、对于带参数列表的函数,必须从右向左添加默认值,也就是说要为某个参数设置默认值,则必须为它右边的所有参数提供默认值。

int harpo(int n, int m = 4, int j = 5); //有效
int chico(int n, int m = 6, int j);     //无效
int groucho(int k = 1, int m = 2, int n = 3); //有效

注意实参是按从左到右的顺序依次被赋给相应的形参,而不能跳过任何参数

beeps = harpo(3, ,8) //无效

8、默认参数

默认参数指的是当函数调用中省略了实参时自动使用的一个值,为1.

//返回一个新的字符串包含前字符串的n个字符.cpp
char *left(const char * str, int n)
{
    if(n < 0)
        n = 0;
    char *p = new char[n+1];
    int i;
    for(i = 0; i < n && str[i]; i++)
        p[i] = str[i];
    while(i <= n)
        p[i++] = ‘\0‘;
    return p;
}

9、函数重载

1)函数重载的关键是函数的参数列表,也称为函数特征标。定义名称相同的函数,条件就是它们的特征标不同。

(函数特征标指如果两个函数的参数数目和类型相同,同时参数的排列顺序也相同,则它们的特征标相同,而变量名是无关紧要的)如果参数数目和或者参数类型不用,那么特征标也不同。

void print(const char * str, int width);
void print(double d, int width)
void print(long l, int width)
void print(int i, int width)
void print(const char *str)

2)举例,前面我们讲了一个char
left(const char str, int n)

所以我们编写一个与前面特征标不同返回整数前n个

//left()返回整数的前几位
unsigned long left(unsigned long num, unsigned ct)
{
    unsigned digits = 1;
    unsigned long n = num;

    if(ct == 0 || num == 0)
        return 0;

    //利用除法来计算数位
    while(n /= 10)
        digits++;

    //每除去10就删除数字的最后一位,要知道需要删除多少位,只需要将总位数减去要获得的位数就可以
    if(digits > ct)
    {
        ct = digits - ct;
        while(ct--)
            num /= 10;
        return num;
    }
    else
        return num;
}

3)虽然函数重载比较诱人,但是不要滥用,只有当函数基本执行相同任务,但使用不同形式的数据时,才采用函数重载。

10、函数模板

现在的C++编译器实现了C++新增的一项特性,叫做函数模板,函数模板是通用的函数描述,也就是说它使用了通用类型来定义函数。如果需要多个将同一个算法用于不同类型的函数,我们使用模板。

//交换模板1.cpp
template <class Any>  //temoplate <typename Any>
void Swap (Any &a, Any &b)
{
    Any temp;
    temp = a;
    a = b;
    b = temp;
}
//交换模板2——交换两个数组中的元素
template <class Any>
void Swap(Any a[], Any b[], int n)
{
    Any temp;
    for(int i = 0; i < n; i++)
    {
        temp = a[i];
        a[i] = b[i];
        b[i] = temp;
    }
}

《C++ Primer Plus》学习笔记3,布布扣,bubuko.com

时间: 2024-10-18 07:40:31

《C++ Primer Plus》学习笔记3的相关文章

C PRIMER PLUS 学习笔记(一)

1显示程序执行的窗口一闪即逝.可以添加如下语句: getchar() 作用是获取键盘输入. 2 inf 和 nan float toobig = 3.4e38 * 100.0f; float not_a_number = asin(1.2);//math.h printf("%e \t %e\n", toobig,not_a_number); inf-表示无穷大,nan-Not-a-number 3 long double 的输出格式 long double x; x = 3.2e-5

C++ Primer Plus学习笔记之虚函数

C++ Primer Plus学习笔记之虚函数 C++语言的多态性有两种类型:静态多态性和动态多态性.函数重载和运算符重载就是静态多态性的具体表现,而动态多态性是指程序运行过程中才动态的确定操作所针对的对象,它是通过虚函数实现的: 1,虚函数的概念: 一个指向基类的指针可用来指向从基类派生的任何对象,这样就可以达到一个接口多个实现的访问了:虚函数是在基类中被冠以virtual的成员函数,它提供了一种接口界面.虚函数可以在一个或者多个派生类中被重新定义,但要求在派生类中从新定义时,虚函数的函数原型

C++ Primer Plus学习笔记之静态成员

C++ Primer Plus学习笔记之静态成员 关键字static可以用来说明一个类的成员(包括数据成员和成员函数),这样的成员被称为静态成员: 1,静态数据成员 在一个类中,若将一个数据说明前加上static,则该数据成为静态数据,静态数据成员被该类的所有对象共享.无论建立多少个该类的对象,都只有一个静态数据存储空间: 具体语法如下: 类型名 类名::静态数据成员[=常量表达式] 其中,常量表达式用于初始化类的静态数据成员: 静态数据成员属于类,而不属于对象,因为静态成员的存在是不依赖于某个

C++ Primer Plus学习笔记之继承类的初始化顺序

C++ Primer Plus学习笔记之继承类的初始化顺序 基类的构造函数,析构函数和操作符函数operator=是不能被派生类继承的: 那么,当创建一个派生类对象时,怎样调用基类的构造函数对基类的数据进行初始化呢??? 答案是:构造函数执行时遵行先兄长(基类),再客人(对象成员),后自己(派生类)的顺序: 另一方面,执行析构函数时,先执行派生类的析构函数,再执行基类的析构函数.原因是,对基类的破坏隐含了对派生类的破坏,所以派生类的析构函数必须先执行: #include<iostream> u

C++ Primer Plus学习笔记之运算符重载

C++ Primer Plus学习笔记之运算符重载 1,成员函数和友元函数选择的建议 下面我们先看两个例子: 成员函数重载 #include<iostream> using namespace std; class Complex { public: Complex(double r=0,double i=0) { re=r; im=i; } Complex operator+(const Complex& obj); Complex operator!(); void Display

C++ Primer Plus学习笔记之拷贝构造函数

C++ Primer Plus学习笔记之拷贝构造函数 1,什么是拷贝构造函数 拷贝构造函数有两个含义: 首先,它是一个构造函数,当创建一个新对象时,系统自动调用它: 其次,它将一个已经定义过的对象的数据成员逐一对应的复制给新对象: 如果一个类没有显式定义拷贝构造函数,C++编译器可以为该类产生一个缺省的拷贝构造函数.这个缺省的拷贝构造函数采用C的方式,将拷贝对象的内存一个字节一个字节的拷贝到拷贝对象的内存中(内存拷贝): 2,拷贝构造函数的作用 (1)创建一个新对象,并将一个已存在的对象拷贝到这

c++ primer plus学习笔记(栈指针)

c++ primer plus 程序清单14.5 程序清单14.6 模拟如下情况: 某人将一车文件交给plodson,如果plodson的收取蓝是空的,他将取出车中最上面的文件,将它放入收 取蓝,如果收取蓝是满的,他将取出栏中最上面的文件,并进行处理,然后放入发出蓝,如果收取蓝不空不满 plodson将采用抛硬币的方式来决定采取措施. 很明显,我们需要使用栈去管理上述文件. 1 #ifndef STACK_H_ 2 #define STACK_H_ 3 4 //定义类模板 5 template

《c++primer》学习笔记

花了一个多月时间总算是把这本书看完了,再去看自己家游戏的服务器的代码还是很难懂,里面用到了好多boost库的东西,不过这些东西很多都已经加入了c++11的新标准里了,要到自己能做服务器还得接着学,所以接下来的一个月开始看<C++标准库>. 把看<c++primer>的时候抄的笔记先誊在这里方便以后参考. #include 来自标准库的头文件使用<> 来自非标准库的头文件使用"" ------------------------------------

c++ primer plus 学习笔记

我的机子用Xcode,单位是字节 0开头为8进制 0x为16进制 cout默认输出的是10进制 wchar_t 宽字节,它是一种足够大的整形类型,可以用来表示的是比如中文的编码 c常量一旦被定义,就不能被修改(const) 浮点数,c++中浮点数在计算内存中由两部分组成,一部分为基数,一部分用来表示浮点,这个浮点是用二进制来表示. 非常大或者非常小的数可以用e表示法来表示 这个程序充分说明了精度的问题,double能保存更高的精度.对于c++来说float只能保存6位有效数字,如果需要更高的精度

《C++ Primer》学习笔记【第一部分 基本语言】

第2章 整型的赋值:当我们试着把一个超出其范围的值赋给一个指定类型的对象时,结果如何?答案取决于类型是signed还是unsigned的.对于unsigned,编译器会将该值对unsigned类型的可能取值数目求模然后取所得值:对于signed类型,未定义行为,很多处理器处理方式和unsigned类似. 字符串字面值的连接:std::cout << "multi-line" L"literal " << std::endl;结果未定义,即连接