C++ Primer 3rd 读书笔记

C++ Primer 3rd 读书笔记1/2

分类: C/C++/VC2014-04-08 20:43 318人阅读 评论(0) 收藏 举报

第一章    开始

1.       C++中标准的头文件是不带.h后缀的。如下代码值得注意:


#include <iostream.h>

void sayHello()

{

cout<<"Hello World!";

}

void main()

{

sayHello();

}


#include <iostream>

using namespace std;

void sayHello()

{

cout<<"Hello World!";

}

void main()

{

sayHello();

}


#include <iostream>

void sayHello()

{

std::cout<<"Hello World!";

}

void main()

{

sayHello();

}

引用带.h的头文件时,不需要使用namespace。引用标准的不带后缀名的头文件时,需要使用namespace。使用namespace有两种方式:1.通过using关键字调用。2.在具体的函数前通过::调用。例如std::cout。

2.    #include称之为预处理器,有两种形式:<>表明文件时标准头文件,查找过程会检查预定义的目录,“”引用的表示该文件时用户提供的头文件,查找文件从当前目录开始,当前目录没有就查找预定义目录。通过如下代码防止重复处理:


#ifndef BOOKSTORE_H

#define BOOKSTORE_H

//content

#endif

使用如下代码判断预处理器常量是否已经被定义:


int main()

{

#indef DEBUG

cout<<”Beginning execution of main()”;

#endif

cout<<”Hello”;

}

如果定义了DEBUGE预编译器常量,那么会编译cout<<”Beginning execution of main()”;如果没有定义DEBUGE,不编译此句。

3.    基本的输入输出流有:cin、cout和cerr。换行输出为cout<<endl;或者cout<<’\n’;

第二章    浏览

1.    在C++中,数组不能直接赋值。而在Java中,数组时可以直接赋值的。

2.    在C++中分为静态(在栈中)和动态(在堆中)分配内存。静态分配在编译时分配,效率高但缺乏灵活性;动态分配在执行时刻分配,效率低但灵活性高。静态对象是有名字的变量,我们直接对其进行操作;动态对象是没有名字的对象,我们通过指针对其进行操作。静态对象的分配和释放由编译器自动处理;动态对象的分配和释放由程序员显式管理,使用的是new和delete。


int *pia = new int(1024);//pia指向单一对象的地址

int *pint = new int[4];//pint指向拥有四个元素数组的第一个元素的地址

delete pia;//删除单一对象

delete []pint;//删除数组

3.    调用对象的方法时,点操作符用于类对象调用,->用于对象指针的调用。

4.    访问函数的开销比直接访问内存的开销大。通过对象的方法访问对象的变量时(访问对象的方法是访问函数,访问对象的变量直接访问内存),C++通过inline机制,将调用函数在调用点展开,节省了开销。

5.    引用是没有指针语法的指针。

6.    类的构造函数用来初始化对象的数据成员,析构函数负责释放对象生命周期内申请到的所有资源。

7.    在继承操作中,基类中需要在子类实现的函数应使用virtual修饰。C++支持多继承。继承关系反映的是is-a的关系。组合关系反映的是hava-a的关系。

第三章    C++数据类型

1.    基本数据类型:

char(1bit)、short(2bit)、int(4bit)、long(4bit)、float(4bit)、double(8bit)

其中char、short、int和long为整型,分为有符号和无符号,默认为有符号。文字常量,例如数字1,其值不能改变,并且不可寻址。相比于文字常量,变量是可以寻址的,每个变量有两个值与其对应,分别是数据值和地址值。

2.    Class A;是声明,声明不是定义,不引起内存分配。

A a(100);静态分配

A *a = new A(100);动态分配

3.    C++中的关键字:


关键字explicit可以禁止“单参数构造函数”被用于自动类型转换

class Stack

{

explicit Stack(int size);

};

没有explicit的话Stack s = 40;能编译通过

而有explicit则不能,必需Stack s(40);


关键字mutable意为:可变的。用于在const的函数里面修改一些跟类状态无关的数据成员


关键字volatile被设计用来修饰被不同线程访问和修改的变量。volatile的作用: 作为指令关键字,确保本条指令不会因编译器的优化而省略,且要求每次直接读值.

4.       基本数据类型变量的初始化:如果该基本类型的变量是在全局域定义的,系统初始化其值为0,如果是局部域或者通过new定义的,系统不对其初始化

5.       对象的初始化支持两种方式。1.int a=100;2.inta(100);

6.       空指针(void*)可以接受任何指针类型的地址值赋值,它表明该值是个地址值,但是该地址值的对象类型不知道,不能知道该指针覆盖的内存区域。

7.    C++提供两种风格的字符串类型,一种是老式的C风格字符串,另一种是标准的C++引入的字符串string。使用老式的C风格字符串需要#include<cstring>,常使用一个char *类型的指针指向。例如char *s=”Hello”;当char *s=0;或者char *s=””;时,其长度为0。老式的字符串使用strlen测定器长度,不包括\0。使用标准C++的字符串string,需要包含头文件#include<string>,使用size()方法获取其长度。通过size()= =0或者empty()方法判断字符串是否为空。string提供对老式C语言中字符串的支持,可以与其运算,可以将老式C语言风格的字符串转换为string类型,反之则不行,需要通过constchar *s = s1.c_str()转换。

8.    对于字符串的赋值。s2=s3;过程如下:首先将s2关联的字符存储区释放掉,然后分配足够存储与s3相关联的字符的存储区,最后将与s3相关联的字符拷贝到该存储区中。注意这里与Java的区别。

9.    const定义变量为常量,使得变量的值不能被修改常量必须初始化非const对象的指针不能指向const对象。const指针可以指向非const变量,此时也不能通过指针修改其值。

A.const int*p=0;//(自右向左)p是一个指向int类型的,被定义为const对象的指针。称之为:指向const的指针指向const的指针可以指向其他,但是不能改变指向的值。const int *p 等价于 int const *p。(const关键字位于第一、第二位置都是指向const的指针)

const double minWage = 0;

p=&minWage;

*p=100;//×指向const的指针可以指向其他,但是不能改变指向的值

double dval=3.14;

p=&dval;

*p=100;//×指向const指针可以指向其他,但是不能改变指向的值

指向const的指针常用在函数的参数中,例如int strcmp(const char *str)用于保证被传递到函数中的实际对象在函数中不被修改。

B.interr=0;int *const cur=&err;//cur是指向int类型的const指针。称之为:const指针const指针不能指向其他的地址值,但是可以修改其值。

C.const double pi=3.14;const double *constpi_ptr=&pi;指向const类型的const指针。


const int aa = 100;

int bb = 200;

int cc = 300;

//指向const的指针

const int *p = &aa;

//*p=100;错误

p=&bb;

//*p=100;错误

//const指针

//int *const pp = &aa;错误,非const类型的指针不能指向const常量

int *const pp = &bb;

//pp=&cc;错误

*pp = 100;

int const * ppp = &aa;

ppp = &cc;

10.  引用是没有指针语法的指针,常用语函数的形参,将类对象传递给函数。引用必须初始化。引用一旦定义,不能指向其他对象。指针所有的操作都被应用在它所指向的对象上。

int a = 100; int&p = a;(指向int型的引用)

int *pi = &a;int *&ppi = pi;(指向指针的引用,&和*作用抵消)

指向const的引用可以使用文字常量初始化,例如:const int &p = 3.14;其内部实现是通过为文字常量定义一个变量,然后引用指向该变量进行实现的。int *pi=0;内部其实为:int tmp=0; const int &ri=tmp;而对于非指向const的引用,由于文字常量不能寻址,因此不能这样初始化(int &p=1;×)。

对于const intival = 1024;定义指向ival指针的引用如下:

const int *const&p = &ival;(第一个const说明指向的是常量,第二个const说明是const指针,只能指向1024的地址,因为文字常量的地址是固定的)

引用与指针的区别;

1.       引用必须总是指向一个对象,必须初始化。指针可以为空。

2.       引用之间相互赋值时,改变的是被引用的对象而不是引用本身。

int &ri = ival, &ri2=ival2;ri=ri2;改变的是ival,而不是引用本身。赋值之后两个引用依然指向原来的对象。

11.    枚举:用于指定一个对象含有指定的几个值。Enum Forms{a=2,b,c}.c=4.

12.    数组维数值必须是常量表达式,必须能在编译期间计算出其值。显式初始化的时候可以不写维数值。字符串也是一个数组,但是其包含了额外的“\0”。数组不能被另一个数组初始化,也不能赋值给另一个数组。C++不提供编译器对数组的边界检查。

13.    数组与指针:数组标示符代表数组中第一个元素的地址,它的类型是数组元素类型的指针。

14.    vector可以被另一个vector初始化,可以赋值给另一个vector。

15.    typedef的一道易错题


Typedef char *cstirng;

Extern const cstring cstr;

问cstr是什么?

不是指向const字符的指针const char *cstr,而是指向char的const指针char * const cstr。

16.  volatile修饰符的作用是告诉编译器,该对象的值可能在编译器未监测到的情况下被改变。因此编译器不能武断地对引用这些对象的代码进行优化处理。

17.  pair提供key-value形式的存储结构,使用需包含<utility>

第四章    表达式

1.    %取模运算符号只能应用于整型操作数上,例如char、short、int和long。

2.    关系和逻辑运算符如果应用在整数值的上下文环境中,会自动提升为1或者0.

3.    不能使用诸如a[index--]<a[index++]的方式,因为C++没有规定程序计算的顺序是从左到右还是从右到左。应该为: a[index--]<a[index+1].

4.    利用i++和++i实现Stack。

Push:stack[top++] = value;

Pop:value = stack[--top];

5.    sizeof操作符的作用是返回一个对象或类型名的长度。当使用sizeof计算数组时,返回的是数组的整个类型长度,而不是第一元素的长度。Sizeof计算指针时,sizeof(p)=4;siziof(*p)=p指向内存元素的类型大小。Sizeof计算引用时,返回的是引用的类型大小。sizeof a和sizeof(a)两种方式都正确。


size_t st;

st = sizeof st;

std::cout<<"st="<<st;

double *sp = new double[3];

int as[] = {1,2,3,4};

std::cout<<"sizeof(sp)="<<sizeof(sp)<<std::endl;

std::cout<<"sizeof(*sp)="<<sizeof(*sp)<<std::endl;

std::cout<<"sizeof(as)="<<sizeof(as)<<std::endl;

std::cout<<"sizeof(double *)"<<sizeof(double *)<<std::endl;

std::cout<<"sizeof(double &)"<<sizeof(double &)<<std::endl;


输出结果为:4、8、16、4、8


此外:sizeof(‘c’)=1;sizeof(“c”)=2;【包含\0】sizeof(std::string)=16;string str =”s”;sizeof(str)=16;

6.    系统为程序分配内存的区域称之为空闲存储区或者堆。使用new执行分配内存的操作。所有从堆中分配的对象都是未命名的,new表达式返回的不是对象本身,而是对象的地址,对象所有的操作都是通过地址值间接完成的。使用delete来删除我们从堆中申请的对象。删除单个元素:delete p;删除数组:delete[] p;

7.    inta = 3;int b = a + 1.24;首先将a提升为double,然后a+1.24得到double的结果,然后将结果转换为int(编译器会报错)。发生隐形转换的情况如下:

1.    混合运算:int a= 3; double d = 3.243; double dd = a + d;

2.    用一种类型的表达式赋值给另一种类型的对象。 a = d;或者 int *p =0;

3.    把一个表达式传递给一个函数调用,表达式类型与参数类型不同。Extern double sqrt(double); cout<<sqrt(2);

4.    从一个函数返回一个表达式,表达式与返回类型不同。Double dif(int a,int b){return a – b;}

8.    算数运算中:

1.    类型总是被提升为较宽的类型。Int->float->double->long double

2.    小于整形的有序类型的算数表达式都转换成整形。例如char、signed char short等。此外还有enum中的值,boo值也被提升为整形int。

9.    显式类型转换常用命令:static_cast(静态转换,一般的转换)、dynamic_cast(运行时刻识别由指针或引用指向的类对象)、const_cast(const常量转换)和reinterpret_cast。显示类型转换的语法为:castname<type>(expression);

旧式强制转换语法:

       1.    C++强制转换符号:type(expr)

       2.    C语言强制转换符号:(type)expr;

10.  任何非const数据类型的指针都可以被赋值为void*。

第五章    语句

1.    string*p, p1;定义p为指针,p1为字符串。string *p,*p1;定义p,p1为指针。

2.    switch如果不加break,则会从入口点一直执行。

3.    break:跳出循环体;continue:跳出本次循环,转而进行洗一次循环。

时间: 2024-10-29 21:24:22

C++ Primer 3rd 读书笔记的相关文章

《C++ Primer》读书笔记—第十三章 控制拷贝

声明: 文中内容收集整理自<C++ Primer 中文版 (第5版)>,版权归原书所有. 学习一门程序设计语言最好的方法就是练习编程 第III部分,类设计者的工具 1.类是C++的核心概念.每个类都定义了一个新类型和在此类型对象上可执行的操作. 2.当定义一个类时,我们显式或隐式地指定在此类型的对象的拷贝.移动.赋值和销毁时做什么.一个类通过定义五种特殊的成员函数来控制这些操作,包括:拷贝构造函数(copy construcor),拷贝赋值运算符(copy-assignment operato

《C++ Primer》读书笔记—第一章 开始

声明: 文中内容收集整理自<C++ Primer 中文版 (第5版)>,版权归原书所有. 学习一门程序设计语言最好的方法就是练习编程. 1.一个函数的定义包含四个部分:返回类型(return type).函数名(function name).一个括号包围的形参列表(parameter list,允许为空)以及函数体(function body). 2.cin.cout的使用 1 #include<iostream> 2 int main() 3 { 4 std::cout <

《C++ Primer》读书笔记—第十六章 模板与泛型编程

---恢复内容开始--- 声明: 文中内容收集整理自<C++ Primer 中文版 (第5版)>,版权归原书所有. 学习一门程序设计语言最好的方法就是练习编程 1.面向对象编程和泛型编程都是处理在编写程序时不知道类型的情况,不同之处在于,OOP能处理类型在程序运行之前都未知的情况,而在泛型编程中,在编译时就能获知类型了. 2.泛型编程与面向对象编程一样,都依赖于某种形式的多态性.面向对象编程中的多态性在运行时应用于存在继承关系的类. 3.在泛型编程中,我们所编写的类和函数能够多态地用于跨越编译

《C++ Primer》读书笔记—第四章 表达式

声明: 文中内容收集整理自<C++ Primer 中文版 (第5版)>,版权归原书所有. 学习一门程序设计语言最好的方法就是练习编程 1.表达式由一个或多个运算对象组成,对表达式求值将得到一个结果.字面值和变量是最简单的表达式,其结果就是字面值和变量的值.把一个运算符和一个或多个运算对象组合起来可以生成复杂的表达式. 2.指针不能转换成浮点数. 3.一个左值表达式的求职结果是一个对象或者一个函数,然而以常量对象为代表的某些左值实际上不能作为赋值语句的左侧运算对象. 4.在除法运算中,如果两个运

C++ Primer Plus读书笔记

第五章 循环和关系表达式 1. 2.类别别名: (1)   #define FLOAT_POINTER float * FLOAT_POINTER pa, pb; 预处理器置换将该声明转换成  float * pa, pb: // pa 是指针,pb就是一个float (2)  typedef char byte 不会出现上述问题是最佳的选择 3.  cin.get(name, arSize).get() // 输入长度为arSize的name接受换行 // 发送给cin的输入被缓冲.这意味着只

C Primer Plus读书笔记-预处理器指令

代码中经常看到  #define ,#ifdef #define :明显常量 一般的指令长度仅限与一行代码,除了\(反斜杠线)可以拓展到下一行外. 一般情况下,每个#define行由三个部分组成. 第一部分为#define 指令本身 第二部分为所选择的缩略语,这些缩略语称为宏(macro).  宏的名字中不允许有空格!只能使用字母,下划线(_),和数字之间的组合,第一个字符不能为数字 第三部分(#define行除了第一第二部分外的部分).称为替换列表或主体. 预处理器在程序中发现宏的实例后,总会

C++ Primer 4th 读书笔记(第一部分)

虽然,有一定的c++基础(因为本科就学会了这一种,哈哈),但是还是决定系统的读一遍这本书(之前有零星看过数次..汗). 留作自己以后参考.(内容会不定期更改,不断学习(此处应为长音~~)) 大部分都是自己掌握的不够扎实的地方和以前没有注意的一些细节. 书中好多地方,详述了知识出现的缘由,最起码是指出为了解决什么问题而出现的!! 前言部分 1."...大量使用了前后交叉引用..."(挺适合自己的,我想知道原文是怎么的,希望以后有机会对原版的时候补充~) 2.作者对本书的定位是本指南性读物

C primer plus 读书笔记第九章

本章的标题是函数.C的设计原则是把函数作为程序的构成模块. 1.函数概述 函数的定义:函数是用于完成特定任务的程序代码的自包含单元. 使用函数的原因:1.函数的使用可以省去重复代码的编写.2.使得程序模块化,更有利于阅读.修改和完善.以这种方式看待函数有利于把精力投入到程序整体设计而不是实现其细节. 函数同变量一样有多种类型.任何程序在使用函数之前都需要声明该函数类型. 函数参数.函数类型没啥说的,其他语言都会讲到. PS:函数的结尾最好只使用一次return,这样更有利于阅读程序的人明白函数的

C primer plus 读书笔记第五章

本章的标题是运算符,表达式和语句.主要研究如何处理数据. 示例代码展示了一个使用简单的while循环的代码,难度不大. 下面简单介绍本章的基本概念. 1.基本运算符. 基本运算符有:赋值运算符(C语言可以多重赋值,例如cheeta = tarzan = 68),加法运算,减法运算符,符号运算符(也称为一元运算符),乘法运算符,除法运算符(整数除法结果的小数部分会丢弃,而整数除浮点数的时候,编译器是先将整数转换为浮点数) 2.其他运算符 有sizeof,size_t,%(注意负数的情况),++,-