c++ primer笔记

1#include <iostream> 这个预编译指令是做什么用的?

这将导致在最终的编译之前,使用iostream文件的内容替换该编译指令

2using namepace 做什么用的?

使得程序可以使用std名称空间中的定义

4、下面函数原型指明了关于函数的那些信息?

int froop(double t);

调用函数froop()时,应提供一个参数,该参数的类型为double,而该函数将返回一个int值。

void rattle(int n);

函数rattle()接受一个int 参数且没有返回值

int prune(void);

函数prune不接受任何参数且返回一个int.

5、如何确定一个整数是2的幂次,不能使用循环

   应该用位操作吧?

6、换行符和 endl的区别?

1)、将换行符嵌入到较长的字符串中时,比endl方便。

2)、显示数字时,使用endl比输入/n更容些,但是显示字符串时,在字符串末尾添加一个换行符所需的输入量要少些。

3)、可以基于字符的八进制和十六进制编码来使用转移序列。

 

7char int 不同的是 char在默认情况下既不是没有符号,也不是有符号。是否有符号有c++实现决定,这样编译器开发人员可以最大限度地将这种类型与硬件属性匹配起来。应显示的定义

8const的做用?

1)定义一个常量2)把函数参数定义为const可以防止改变该参数,这样可以减少或避免bug3)能够时程序显得更加紧凑性

9const#define 定义常量有什么区别?

const 首先明确指定了类型,其次,可以使用c++的作用域规则将定义限制在特定的函数或文件中。最后,可以将const用于更复杂的类型

10ostream方法---setf(),这种调用迫使输出使用定点表示法,以便更好地了解精度,它防止程序把较大的值切换为E表示法,并使程序显示到小数点后6位小数。

11、浮点数的优缺点:1)优点:可以表示整数之间的值。由于有缩放因子,可以表示的范围大得多。

     缺点:运算速度比证书运算慢,精度将降低。

12、操作符重载简介?

   除法表示了3种不同的运算:int float double除法,c++根据上下文来确定操作符的含义。使用相同的符号进行多种操作叫做操作符重载。还可以扩展操作符重载,以便能够用于用于用户定义的类

13、强制类型转换不会修改变量本身,而是创建一个新的、指定类型的值,可以在表达式种使用这个值。

14、强制类型转换的通用格式如下:(17章详解)

    (typeName)value  来自C语言

    typeName (value) 来自c++,想法是:要让强制类型转换就像是函数调用。这样内置类型的强制类型转换操作符就是为用户定义的类设计的类型转换。

4个强制类型操作符:static_cast<>可用于将值从一种数值类型转换为另一种数值类型。

15、为什么C++有种整型?

  有多种整型类型,可以根据特定需求选择最适合的类型。例如,可以是哟个short来存储空格,使用来确保存储容量,也可以寻找可提高特定计算速度的类型。

16c++没有提供自动防止超出整型限制的功能,可以使用头文件climits来确定限制情况。

17、下面语句是否等价?

  char grade=65;

  char grade='A';

这两条语句并不真正等价,虽然对于某些系统来数,它们是等效的。最重要的是,只有在使用ASCII码的系统上,第一条语句才将得分设置为字母A,而第二条语句还可用于使用其他编码的系统。其次,65是一个int常量,而'A'是一个char常量。

18、将long值赋给float会导致误差,将long赋给double呢?

  这个问题取决于这两个类型长度。如果long4个字节,则没有损失。因为最大的long值将是20亿,既有10位整数。由于double提供了至少13位有效数字,因而不需要进行任何舍入。

19、为什么使用get(),而不是getline()呢?

  首先老式实现没有getline()。其次,get()使输入更仔细。还有getline()使用起来更简单一些,但get()使得检查错误更简单些。

20、当getline() get()读取空行时,将发生什么情况?

   get()读取空行后将设置失效位(failbit)。意味着接下来的输入将被阻断,但可以用下面的命令来恢复输入:cin.clear();

  另一个潜在的问题是,输入的字符串可能比分配的空间长。如果输入行包含的字符数比指定的多,则getline()get()将把余下的字符留在输入队列中,而getline()还会设置失效位,并关闭后面的输入。

30、头文件cstringstring 有什么区别?

31strlen()string.size()有什么区别和联系?

   都是计算字符串的实际长度。不同的是:string十一哥对象,不是被用作函数参数,而是位于函数名之前,它们之间用句点连接。可得出,C函数使用参数来指出要使用哪个字符串,而c++ string类对象使用对象名和句点操作符来指出要使用哪个字符串。

31C的结构体和C++中的结构体有什么区别?

  首先c++可以忽略struct关键字,还有一个c++结构中可以申明函数。结构可以将比如string类作为成员,(相同之处:可以将结构作为参数传递给函数,也可以让函数返回一个结构),与C不同的是,结构可以直接赋值。

32、只为枚举定义了赋值操作,但是没有定义算数操作,也就是枚举中的常量不能进行诸如加减之类的运算。枚举的取值范围定义如下:首先找出上限,需知道枚举量的最大值。找到大于这个最大值的,最小的2的幂,将它减去1,得到的彼岸时取值范围的上限。

33、面向对象和面向过程的区别?

   二者区别在于:OOP强调的是在运行阶段(而不是编译阶段)进行决策。运行阶段指的是程序正在运行时,编译阶段指的是编译器将程序组合起来。运行阶段提供了灵活性,可以根据当时的情况进行调整。

处理存储数据的新策略是将地址视为指定的量,而将值视为派生量。

34、在c++中创建指针时,计算机将分配用来存储地址的内存,但不会分配用来存储指针所指向的数据内存。因此一定要在对指针应用解除引用操作符(*)之前,将指针初始化为一个确定的,适当的地址。

35、使用newdelete应注意的是:

  不要使用delete来释放不是new分配的内存。不要使用delete释放同一个内存块两次。如果使用new[]为数组分配内存,则应使用delete[]来释放。如果使用new[]为一个尸体分配内存,则应使用delete(没有方括号)来释放。对空指针应用delete是安全的。

36、区分指针和指针所指向的值

  如果pt是指向int的指针,则*pt不是指向int的指针,而是完全等同于一个int类型的变量。

37、在cout和多数c++表达式中,char数组名、指向char的指针以及用引号括起的字符串常量都被解释为字符串第一个字符的地址。

38c++C循环的基础上添加了一项特性:

  c++允许进行如下操作:for(int i=0;i<5;i++),即,就是在for循环的初始化部分中声明变量。但是这种变量只存在于for语句中,也就是说,当程序离开循环后,这种变量将消失。还有下面的语句也是合法的:for(for-init-statement conditon;expression)此处for-init-statement被视为一条语句,而语句有自己的分好。对于for-init-statement来说,他既可以是表达式语句,也可以是声明,这种句法规则用语句替换了后面跟分号的表达式,语句本身邮资机的分号。

39、重载与覆盖的区别

1、方法的覆盖是子类和父类之间的关系,是垂直关系;方法的重载是同一个类中方法之间的关系,是水平关系。

2、覆盖只能由一个方法,或只能由一对方法产生关系;方法的重载是多个方法之间的关系。

3、覆盖要求参数列表相同;重载要求参数列表不同。

4、覆盖关系中,调用那个方法体,是根据对象的类型(对象对应存储空间类型)来决定;重载关系,是根据调用时的实参表与形参表来选择方法体的。

40、关于c++递增操作符何时生效做了哪些方面的规定,哪些方面没有规定?

   首先,副作用指的是在计算表达式时对某些东西(如存储在变量中的值)进行了修改;顺序点是程序执行过程中的一个点,在这里,进入下一步之前将确保对所有的副作用都进行了评估。

  何为完整表达式呢?1)、表达式语句中的表达式部分以及用作while循环检测条件的表达式。

例子:while(i++<10)

        printf("%d/n",i);

  在这个例子中,表达式i++<10是一个完整表达式,因为它是一个while循环的测试条件,因此该表达式的末尾是一个顺序点。所以,c++确保副作用(i1)在程序进入printf()之前完成。然而,通过使用后缀格式,可确保将i10进行比较后再将其值加1.

y=(4+x++)+(5+x++);

 表达式4+x++不是一个完整的表达式,因此c++不保证x的值在计算子表达式4+x++后立即增加1。在这个例子中,整条赋值语句是一个完整表达式,而分号标示了顺序点,因此c++只保证程序执行到一条语句之前,x的值将被递增两次。

41forwhile的不同与相同?

二者本质上相同的,只不过是书写方式不同而已,for需要3个表达式,而while只需要一个就足以了。

for循环的一个优点是其结构气功了一个可实现3条指导原则的地方(原则:确定循环终止的条件、在首次测试之前初始化条件、在条件再次测试之前更新条件)

42、检测到EOF后,cin将两位(eofbitfailbit)都设置为1,可以通过成员函数eof()来查看eofbit是否被设置;如果检测到EOF,cin.eof()将返回booltrue,否则返回false.如果eofbitfailbit被设置为1,则fail()成员函数返回TRUE,否则返回false。注意,eof()fail()方法报告最近读取的结果;也就是说,它们在事后报告,而不是预先报告。一次将cin.eof()cin.fail()测试放在读取后。如:

   cin.get(ch);

   while(cin.fail()==false) // while(!cin.fail())

   {                            //while(ch!=EOF)

     ....               //while(cin.get(ch)) 因为cin.get(char)的返回值为cin

     cin.get(ch);          //while((ch=cin.get())!=EOF)

   }

43、入口条件循环和出口条件循环之间的区别?各种c++循环分别属于其中的哪一种?

   输入条件循环在进入输入循环体之前将评估测试表达式。如果条件最初为false,则循环不会执行其循环体。退出条件循环在处理循环体之后评估测试表达式。因此,即使测试表达式最初为false,循环也将执行一次。forwhile都是输入循环,而do while 是退出循环。

44、如果使用整数标签,且用户输入了非整数(q),则程序将因为整数输入不能处理字符而挂起。但是如果使用字符标签,而用户输入了整数(5),则字符输入将5作为字符处理。然后,switch语句的default部分将提示输入另一个字符。

45cout.setf(ios_base::fixed,ios_base::floatfield);

这种调用迫使输出使用定点表示法,以便更好地了解精度,

它防止程序把较大的值切换为E表示法,并使程序显示到小数点后6位小数。

cout.setf(ios_base::boolalpha);使输出为truefalse.

46  int val=int(10)相当于int val=10;但是二者有什么区别?

47   continue语句导致改程序跳过循环体的剩余部分,但不会跳过循环的更新表达式。

比如:在for循环中,continue语句使程序直接跳到更新表达式处,然后跳到测试表达式处。

不过对于while循环来说,continue将使程序直接跳到测试表达式处,因此循环体中位于continue之后

的更新表达式都将被跳过。

48、如下语句

   int n;

   cin >> n;

  如果用户输入的使一个单词而不是一个数字时,发生哪些情况?

n的值保持不变

不匹配的输入将被留在输入队列中

cin对象中的一个错误标记被设置

cin方法的调用将返回false(如果被转换为bool类型)

方法返回false意味着可以用非数字输入来结束读取数字的循环。非数字输入设置错误标记意味着必须重置该

标记,程序才能继续读取输入。clear()方法重置错误输入标记,同时也重置文件尾(EOF条件).错误输入和EOF都将导致cin返回false.

49cout 输出的格式化方法:setf()precision()这些方法只影响调用它们的对象。

 注意:打开已有的文件,已接受输出时,默认将它其长度截断为零,因此原来的内容将丢失。

  对象名.is_open()用来判断文件是否打开,打开的话就会返回true,若没有打开的话就会返回false.

也可以用 对象名.good()来检查文件是否打开,但是没有前者严格。

需要注意的是文件读取循环正确设计:读取文件时,有几点需要检查。首先,程序读取文件时不应超过EOF。如果最后一次读取数据遇到EOF,方法eof()将返回TRUE。其次,程序可能遇到类型不匹配的情况,如果遇到则方法fail()将返回true。最后,某些预期外的东西可能出现问题,例如文件受损或硬件故障,如果最后一次读取文件时发生了这样的问题,方法bad()将返回TRUE。不要分别检查这些情况,一种简单的方法是使用good()方法,该方法在没有发生任何错误时将返回true

50、函数是如何返回值的?通常函数通过将返回值复制到指定的cpu寄存器或内存单元中来将其返回。随后,调用程序将查看该内存单元。返回函数和调用函数必须就该内存单元中存储的数据的类型达成一致。函数原型将返回值类型告知调用程序,而函数定义命令被调用函数应返回什么类型的数据。

51、内联与宏:

  C语言使用预处理器语句#define 来提供宏----内联代码的原始实现。

#define SQUARE(x) x*x;  注意这不是通过传递参数实现的,而是通过替换文本实现的--x是“参数”的符号标记。宏不能按值传递,即使用新的定义,SQUAREc++)仍将C递增两次,但是内联函数不是这样的。

52、引用是已定义的变量的别名(另一个名称)。引用变量主要用途是用作函数参数。通过将引用变量用作参数,函数将原始数据,而不是其拷贝。

  引用和指针的区别:除了表示法不同之外,还有:必须在声明引用时将其初始化,而不能像指针那样,先声明,在赋值。

  引用更接近const 指针,必须在创建时进行初始化,一旦与某个变量关联起来,就将一直效忠与它。

比如:int &rodents=rats; 实际上是下述代码的伪装表示:int * const pr=&rats;其中引用rodents扮演的角色与表达式*pr相同。

52c++的递归和C不同的是:c++不允许main()调用自己。

53estimagte()中一部分代码都是相同的,该函数允许每个程序员提供自己的算法来估算时间。为实现这种目标,采用的机制是,将程序员要使用的算法函数的地址传递给estimate()。为此必须能够完成下面的工作:

  1)获取函数的地址;2)声明一个函数指针;3)使用函数指针来调用函数。

 赋值与C类似,但是也有区别:比如

 double pam(int);

 double (*pf)(int);

 pf=pam;

 double x=pam(4);

 double y=(*pf)(5);

可以用下面使用pf:double y=pf(5);由此说明:pf(*pf)等价!!!

54、使用函数的步骤:

1)定义函数2)提供原型3)调用函数

55、为什么不对类型为基本类型的函数参数使用const限定符?

const限定符用于指针,以防止指向的原始数据被修改。程序传递基本类型时,它将按值传递,以便函数使用副本。这样原始数据将得到保护。

56、按值传递它,只要传递结构名glitz即可。要传递它的地址,请使用地址操作符&glitz。按值传递自动保护原始数据,但这是以时间和内存为代价的。按地址传递可节省时间和内存,但不能保护原始数据,除非对函数参数使用了const限定符。另外,按值传递意味着可以使用常规的结构成员表示法,但是传递指针则必须使用简介成员操作符。

57c++内联函数:是C++为提高程序运行速度所做的一项改进。常规函数和内联函数主要区别不在于编写方式,而在于c++编译器如何将它们组合到程序中。

常规函数调用使程序跳到另外一个地址(函数地址),并在函数结束时返回。下面是这一过程的典型实现:执行到函数调用指令时,程序将在函数调用后立即存储该指令的内存地址,并将函数参数赋值到堆栈(为此保留的内存块),跳到标记寒素起点的内存单元,执行函数代码(也许还需将返回值放入到寄存器中),然后跳回到地址被保存的指令出。来回跳跃并记录跳跃位置意味着以前使用函数时,需要一定的开销。

内联函数的编译代码与其他程序代码"内联"起来了。也就是说,编译器将使用相应的函数代码替换函数调用。对于内联代码,程序无需跳到另一个位置处执行代码,然后再调回来。因此内联函数的运行速度比常规函数快,但是代价需要占更多的内存。

应有选择地使用内联函数。如果执行函数代码的时间比处理函数调用机理的时间长,则所节省的时间将只占整个过程的很小一部分。如果代码执行时间很短,则内联调用就可以节省非内联调用使用的大部分。

58、按值传递和按引用传递的区别:

1)声明函数参数方式不同2)内在的区别是:两个引用变量交换,即交换别名,相当于交换两个变量的值

    按引用触底和按地址传递区别:1)声明函数参数的方式不同。2)定义引用变量必须进行初始化。

59、引用的属性和特别之处:

   引用对于参数的限制更严格些。比如一个函数:double z=cube(x+2.0);因此如果ra是一个变量的别名,则实参应是该变量。但是不会产生错误,由于x+2.0不是double类型的变量,因此程序创建一个临时的无名变量,并将其初始化为表达式x+2.0的值。然后ra将成为该临时变量的引用。

 也就是说实参与引用参数不匹配,c++将生成临时变量。仅当参数为const引用时,c++才允许这样做,但是这是一种新的限制。

什么时候创建临时变量?如果引用参数是const,则编译器将在下面两种情况下生成临时变量:

1)实参的类型正确,担不是坐直。2)实参的类型不正确,但可以转换为正确的类型。

 总之,如果接受引用参数的函数的意图是修改作为参数传递的变量,则创建临时变量将阻止这种意图的实现。解决的方法是:禁止创建临时变量。

但是引入引用主要是为了用于结构和类的,而不是基本的内置类型。通常将返回的引用声明为const是最好的选择。

  三个领域:1)使用指向结构的引用2)将引用作为返回值。通常返回机制将返回值父子到临时存储区域中,随后调用程序将访问该区域。然而,返回引用意味着调用程序将直接访问返回值,而不需要拷贝。通常,引用将指向传递给函数的引用,一次调用函数实际上是直接访问自己的一个变量。注意:返回引用的函数实际上是被引用的变量的别名。3)使用函数调用来访问结构的成员。

  返回引用需要注意的问题:因避免返回当函数终止时不再存在的内存单元引用。比如:

  const sysop & clone2(sysop & sysopref)

  {

    sysop newguy;

    newguy = sysopref;

    return newguy;

  }

  为避免这种问题,最简单的办法返回一个作为参数传递函数的引用。作为参数的引用将指向调用函数使用的数据,因此返回的引用也将指向这些数据。另一种发那个发是用new来分配的存储空间。

60、为何将返回的引用声明为const?它不意味着结构sysop本身const,而只意味着不能使用返回的引用来直接修改它指向的结构。所以应避免在设计中添加模糊的特性,因为么模糊特性增加了特性的机会。

61、使得能够将特性从一个类传递到另一个类的语言特性被称为继承。继承的另一个特性:基类引用可以指向派生类对象,而无需进行强制类型转换。这样,可以定义一个接受基类引用作为参数的函数,调用该函数时,可以将基类对象作为参数,也可以将派生类对象作为参数。

62、方法setf()让您能够设置各种格式化状态。setf(ios_base::fixed)将对象置于使用定点表示法的模式;setf(ios_base::showpoint)将对象置于显示小数点的模式,即使小数部分为零。precision()指定显示多少位小数(假定对象处于定点模式下)width()方法设置下一输出操作使用的字段宽度,这种设置只显示下一个值时有效,然后将恢复到默认设置。默认的字段宽度为零,这意味着刚好能容纳下要显示的内容。

两个有趣的方法调用:

ios_base::fmtflags initial;

initial=os.setf(ios_base::fixed);

...

os.setf(initial);

方法setf()返回调用它之前有效的所有格式化设置。ios_base::fmtflags是存储这种信息所需的数据类型名称。因此,将返回值赋给initial将存储调用file_it()之前格式化设置,然后便可用变量initial作为参数来调用setf(),将所有的格式化设置恢复的原来的值。

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

1)程序员能够修改调用函数中的数据对象。2)通过传递引用而不是整个数据对象,可以提高程序的运行速度。

对于什么时候使用引用,什么时候使用指针呢?什么时候又应按值传递呢?下面一些知道原则:

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

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

2)如果书记对象是数组,则是哟个指针,这是唯一的选择,并将指针声明为指向const的指针。

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

4)如果数据类型是类对象,则使用const引用。类设计的语义常常要求使用引用。

对于修改调用函数中数据的函数:

1)如果数据对象是内置数据类型,则使用指针。如果看到诸如fixit(&x)这样的代码(其中xint),则很明显,该函数将修改x.

2)如果数据对象是数组,则只能使用指针。

3)如果数据对象是结构,则使用引用或指针。

4)如果数据对象是类对象,则使用引用。

64、使用默认参数极大地提高了使用函数的灵活性。设置默认值必须通过函数原型。对于带参数列表的函数,必须从右向左田间默认值。也就是说,要为某个参数设置默认值,则必须为它右边的所有参数提供默认值。在设计类时,就会发现,通过使用默认参数,可以减少要定义的析构函数,方法以及方法重载的数量。

65、默认参数能够使用不同目的参数调用同一个函数,而函数多态(函数重载)让你能够使用多个同名的函数。c++使用上下文来确定要使用的重载函数版本。

66、函数重载的关键是函数的参数列表——也称为函数特征标。注意,是特征标,而不是函数类型使得可以对函数重载。仅当函数基本上执行相同任务,但使用不同形式的数据时,才采用函数重载。

67、函数模板是通用的函数描述,也就是说,它们使用通用类型定义函数,其中的通用类型可用具体的类型(intdouble)替换。

定义如下:

  template <class或者typename Any>

  void function(Any any)

  {

    ...

  }

其中typenameclass是等价的。但是如果需要多个将同一种算法用于不同类型的函数,应使用模板,如果不考虑向后兼容的的问题,并愿意键入较长的单词,则声明类型参数时,应使用关键字typename而不使用class。同样模板函数也支持重载。

 

68c++允许将一个结构赋给另一个结构,因此即使Any是一个job结构。但是指向交换某一成员,而不交换其他成员时,则需要不同的代码,因此无法使用模板重载来提供其他的代码。但是可以提供一个具体化函数定义--称为显示具体化(explicit sepcialization)其中包含所需的代码。当编译器找到与函数调用匹配的具体化定义时,将使用该定义,而不再寻找模板。

69c++试验了本章后面将介绍的具体化方法后,c++标准选择了下面的方法:

1)对于给定的函数名,可以有非模板函数、模板函数显式具体化模板函数以及它们的重载版本。

2)显式具体化的原型和定义应以template<>打头,并通过名称来指出类型。

3)具体化将覆盖常规模板,而非模板函数将覆盖具体话和常规模板。

void Swap(job &,job &); 非模板函数

template <class Any>模板函数

void Swap(Any &,Any &);

template <> void Swap<job>(job &,job &)或者template <> void Swap(job &,job &); 具体化模型。

如果有多个模型,则编译器在选择模型时,非模板版本将优先与显式具体化和模板版本,而显式具体的话将优先于使用模板生成的版本。

70、实例化和具体化:

  在代码中包含函数模板本身并不会生成函数定义,它只是一个用于生成函数定义的方案。编译器使用模板特定类型生成函数定义时,得到的是模板实例(intantiation)。模板并非是函数定义,但使用int的模板实例是函数定义。这种实例化方式称为隐式实例化,因为编译器之所以知道需要进行定义,是由于程序调用swap()函数提供了int参数。

显式实例化的句法是:声明所需的种类--<>符号只是类型,并在声明加上关键字template

       template void Swap<int>(int,int);

与显式实例化不同的是:

      template <> void Swap<int>(int &,int &);

       template <> void Swap(int &,int &);

区别在于:这些声明的意思是“不要使用Swap()模板来生成函数定义,而应使用独立的、专门的函数定义显式地为int类型生成函数定义”。这些原型必须有自己的函数定义。显式具体化声明template后包含<>,而显式实例化没有。注意:试图在同一个编程单元使用同种类型的显式实例和显式具体化将出错。

相同之处:表示的都是使用具体类型的函数定义,而不是通用描述。

代码片段总结:

...

template <class Any>

void Swap(Any &,Any &);

 

template <> void Swap<job>(job &,job &);

int

main(void)

{

  template void Swap<char>(char &,char &);//显式实例化

  short a,b;

  ...

  Swap(a,b);//隐式实例化

  job n,m//结构

  ...

  Swap(n,m);//显式具体化

  char g,h;

  ...

   Swap(g,h);//显式实例化

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值