Nowcoder专项练习:C++(十四)

1,函数模板

函数模板是C++新增的一种性质,它允许只定义一次函数的实现,即可使用不同类型的参数来调用该函数。这样做可以减小代码的书写的复杂度,同时也便于修改。但是,在代码中包含函数模板本身并不会生成函数定义,它只是一个用于生成函数定义的方案。编译器使用模板为特定类型生成函数定义时,得到的是模板实例(instantiation)。

  • 函数模板必须由编译器根据程序员的调用类型实例化为可执行的函数。
  • 类模板的成员函数都是函数模板。
  • 没使用过的成员函数(即函数模板)不会被实例化。

2,#import与#include

Objective-C 中 #import 和 #include 的区别:
预编译指令
Objective-C:#import
C,C++:#include

#import由gcc编译器支持
在 Objective-C 中,#import 被当成 #include 指令的改良版本来使用。除此之外,#import 确定一个文件只能被导入一次,这使你在递归包含中不会出现问题。

使用哪一个还是由你来决定。一般来说,在导入 Objective-C 头文件的时候使用 #import,包含 C 头文件时使用 #include。
#import比起#include的好处就是不会引起交叉编译。


3,CreateThread()与_beginthreadex()

CreateThread()函数是Windows提供的API接口,在C/C++语言另有一个创建线程的函数_beginthreadex(),在很多书上(包括《Windows核心编程》)提到过尽量使用_beginthreadex()来代替使用CreateThread(),这是为什么了?下面就来探索与发现它们的区别吧。
首先要从标准C运行库与多线程的矛盾说起,标准C运行库在1970年被实现了,由于当时没任何一个操作系统提供对多线程的支持。因此编写标准C运行库的程序员根本没考虑多线程程序使用标准C运行库的情况。比如标准C运行库的全局变量errno。很多运行库中的函数在出错时会将错误代号赋值给这个全局变量,这样可以方便调试。但如果有这样的一个代码片段:

if (system("notepad.exe readme.txt") == -1)  
{  
   switch(errno)  
   {  
       ...//错误处理代码  
   }  
}  

假设某个线程A在执行上面的代码,该线程在调用system()之后且尚未调用switch()语句时另外一个线程B启动了,这个线程B也调用了标准C运行库的函数,不幸的是这个函数执行出错了并将错误代号写入全局变量errno中。这样线程A一旦开始执行switch()语句时,它将访问一个被B线程改动了的errno。这种情况必须要加以避免!因为不单单是这一个变量会出问题,其它像strerror()、strtok()、tmpnam()、gmtime()、asctime()等函数也会遇到这种由多个线程访问修改导致的数据覆盖问题。
为了解决这个问题,Windows操作系统提供了这样的一种解决方案——每个线程都将拥有自己专用的一块内存区域来供标准C运行库中所有有需要的函数使用。而且这块内存区域的创建就是由C/C++运行库函数_beginthreadex()来负责的。

_beginthreadex()比较于 CreateThread()有更高的线程安全性,不会造成多个线程共用同一个全局变量的情况。


4,转义字符

在这里插入图片描述
Q:
语句printf(“a\bre\’hi\’y\\bou\n”);的输出结果是:

A:
首先要明确该字符串中包含的转义字符,”a \b re \’ hi ’ y \ \b ou \n”中的转义字符(带下划线的部分)共有6个,其中’\b’是退格符,输出时将光标往左边回退一个位置,
‘\’’为单引号字符,’\’为\字符,’\n’为回车换行符。

因此,最后的结果为:

  • re’hi’you

5,析构函数的调用顺序

Q:

C c;
void main()
{
    A*pa=new A();
    B b;
    static D d;
    delete pa;
}

析构函数的调用顺序是?

A:
这道题主要考察的知识点是 :全局变量,静态局部变量,局部变量空间的堆分配和栈分配

其中全局变量和静态局部变量时从静态存储区中划分的空间,
二者的区别在于作用域的不同,全局变量作用域大于静态局部变量(只用于声明它的函数中),
而之所以是先释放 D 再释放 C的原因是, 程序中首先调用的是 C的构造函数,然后调用的是 D 的构造函数,析构函数的调用与构造函数的调用顺序刚好相反。

局部变量A 是通过 new 从系统的堆空间中分配的,程序运行结束之后,系统是不会自动回收分配给它的空间的,需要程序员手动调用 delete 来释放。

局部变量 B 对象的空间来自于系统的栈空间,在该方法执行结束就会由系统自动通过调用析构方法将其空间释放。

之所以是 先 A 后 B 是因为,B 是在函数执行到 结尾 “}” 的时候才调用析构函数, 而语句 delete a ; 位于函数结尾 “}” 之前。

因此,对于这道题,析构函数的调用顺序为:

  • A B D C

6,类型转换

类型转换的原则:根据当前运算符的操作数进行判断,步骤为:
1,整型提升:把小整形转为int以上的大整形。
2,算术转换:将两者中宽度较小的转换为宽度较大的一方。
3,符号转换:如果其中的无符号类型宽度大于等于带符号类型,则把带符号类型转为无符号类型;否则把无符号类型转为带符号类型。


7,静态数据成员

在C++中规定,在建立对象执勤啊就可以为静态数据成员进行赋值。同时规函数定在静态成员函数中,不能使用this指针;静态成员在类外定义时,不需要使用static前缀;

静态成员函数既可以在类内定义也可以在类外定义。


8,C语言中的数据类型

C语言中,最简单的数据类型包括:
整型、实型、字符型

需要注意的是,C语言中没有bool类型。


9,protected

对于protected成员而言:

  • 从公有和保护继承的派生类继承的子类中可以访问的基类的protected成员。
  • 派生类可以定义一个同名的非protected成员。
  • 派生类的可以访问基类对象的公有protected成员。

“派生访问说明符对于派生类的成员(及友元)能否访问其直接基类的成员没什么影响。对基类成员的访问权限只与基类中的访问说明符有关。”“派生类访问说明符的目的是控制派生类用户对于基类成员的访问权限。”
可见,即使是private继承,派生类成员也是可以访问基类的public和protected成员的,只是这些成员在派生类里都为private性质的(就好像普通的类成员可以访问自己类里的私有成员一样),而派生类构造的对象不能访问(就好像在类外访问类中的私有成员)。


10,死代码

所谓死代码,指的是永远都不会被执行到的代码,而不是直接抛弃被注释的代码。


  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值