牛客Day 5

本文介绍了C++编程中的一些关键概念和最佳实践,如内联函数用于提升效率,宏定义的注意事项,引用和指针的区别,const成员函数的特性,线程安全问题,以及虚函数和多态的应用。还涵盖了C++中的类型定义、内存管理、多线程、异常处理、模板、文件操作、预处理器指令等知识点。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1.在一个函数中,要求通过函数来实现一种不太复杂的功能,并且要求加快执行速度,选用内联函数
2.关于C/C++的宏定义:
宏定义不检查参数正确性,会有安全隐患
宏的嵌套定义过多会影响程序的可读性,而且很容易出错
相对于函数调用,宏定义可以提高程序的运行效率
3.引用不可以是void类型
4.指针++和i++是类似的。
因为i++在计算时,会用到中间变量存储,会占用更多的内存和时间。所以++i更好。
5.const修饰类的成员函数形式为:
int Function() const;
该函数特性: 不能修改任何的成员变量;不能调用非const成员函数(非const成员函数可以修哥成员变量)
6.有关c++线程安全:
线程安全问题都是由全局变量及静态变量引起的
若每个线程中对全局变量、静态变量只有读操作,而无写操作,一般来说,这个全局变量是线程安全的;若有多个线程同时执行写操作,一般都需要考虑线程同步,否则的话就可能影响线程安全
POSIX线程标准要求C标准库中的大多数函数具备线程安全性
7.算法5大特征:确定性,能行性,输入,输出,有穷性/有限性
缺少一不可
8.关于do循环体while(条件表达式)条件表达式的执行次数与循环体的执行次数无关
9.关于 typedef :
用typedef可以定义各种类型名,但不能定义变量
用typedef只是将已存在的类型用一个新的名称代替
使用typedef便于程序的通用
10.指针和引用:
指针通过某个指针变量指向一个对象后,对它所指向的变量间接操作。程序中使用指针,程序的可读性差;而引用本身就是目标变量的别名,对引用的操作就是对目标变量的操作。
11.基类中说明了虚函数后,派生类中起对应的函数可以不必说明为虚函数​
12.有关volatile:
当读取一个变量时,为提高存取速度,编译器优化时有时会先把变量读取到一个寄存器中;以后再取变量值时,就直接从寄存器中取值
优化器在用到volatile变量时必须每次都小心地重新读取这个变量的值,而不是使用保存在寄存器里的备份
volatile适用于多线程应用中被几个任务共享的变量
13.基类的公有成员是其公有派生类的公有成员
14.父类的析构函数是非虚的,但是子类的析构函数是虚的,delete子类对象指针会调用父类的析构函数
15.对于派生类的构造函数,在定义对象时构造函数的执行顺序为?
1:成员对象的构造函数
2:基类的构造函数
3:派生类本身的构造函数
213
16.通用多态是包含多态和参数多态
17.文件指针是程序中用FILE定义的指针变量
18.有关友元函数与成员函数:
友元函数可以让本类和友元类对象调用
友元函数和类的成员函数都可以访问类的私有成员变量或者是成员函数
类的成员函数是属于类的,调用的时候是通过指针this调用的
19.关于C++的类:
对基类成员的访问必须是无二义性的
派生类一般都用公有派生
20.C 语言中的文件类型只有ASCII码文件和二进制文件两种
21.关于虚函数的说法:
静态函数不可以是虚函数
虚函数可以声明为inline
22.关于操作系统heap与stack说法:
heap一般由程序员分配和释放,若程序员不释放,可能会造成操作系统的内存泄露
stack由系统自动分配,无需程序员干涉,heap需要手动申请
23.在不同的函数中可以使用相同名字的变量
函数中的形式参数是局部变量
在一个函数内定义的变量只在本函数范围内有效
24.关于STL:
STL容器是线程不安全的
当容量不够时,vector内部内存扩展方式是翻倍
std::bitset不是一个STL容器
std::stack默认是用deque实现的
std::string中可以存储多个’\0’字符
25.关于static:
声明静态全局变量
声明静态函数
声明静态局部变量
26.若有以下的定义:int t[3][2];能正确表示t数组元素地址的表达式是 t[2]
27.由&&构成的逻辑表达式与由||构成的逻辑表达式都有”短路”现象
28..h头文件中的ifndef/define/endif 的作用?防止重复引用
29.一个空类默认一定生成构造函数,拷贝构造函数,赋值操作符,引用操作符,析构函数
30.关于基类和派生类:派生类除了继承基类的成员,还可以定义新的成员
31.有关c++ traits:
一个traits包括了enum、typedef、模板偏特化(template partial specialization)
typedef定义了各个类的各自不同的类型定义
模板偏特化用于实现各个类的不同功能
当函数,类或者一些封装的通用算法中的某些部分会因为数据类型不同而导致处理或逻辑不同,traits会是一种很好的解决方案
32.函数的定义不可以嵌套,函数的调用可以嵌套
33.回调函数:
回调函数就是一个通过函数指针调用的函数
回调函数可能被系统API调用一次,也可能被循环调用多次
回调函数可用于通知机制
34.关于模板:
类模板中的成员函数不全是模板函数
35.对象数组:
对象数组的下标是从 0 开始的
对象数组的数组名是一个常量指针
对象数组的每个元素是同一个类的对象
36.在 C++ 中,用于实现动态多态性的是虚函数
37.在C的文件操作中,可以利用fseek函数进行文件指针的随机定位
38.按照标识符的要求,(连接符)符号不能组成标识符。
39.try块不可以省略
可以使用多重catch块
finally块可以省略
40.基类中的成员在派生类中都是可以直接访问的.说法是否正确?错误
例如公有派生,子类只能访问父类的保护成员和公有成员,父类的私有成员是不能被子类访问的。
41.switch语句能够改写为if语句
42.虚函数不可以内联,因为虚函数是在运行期的时候确定具体调用的函数,内联是在编译期的时候进行代码展开,两者冲突,所以没有一起使用的做法。
43.关于异常处理:
C++语言的异常处理机制通过3个保留字throw、try和catch实现。
任何需要检测的语句必须在try语句块中执行,并由throw语句抛出异常。
throw语句抛出异常后,catch利用数据类型匹配进行异常捕获。
44.C++类体系中,不能被派生类继承的有?构造函数
静态成员函数 赋值操作函数
45.模板的使用实际上是将类模板实例化成一个类
46.C语言本身没有输入输出语句
47.静态数据成员可以直接用类名调用
48.Java不支持指针,C/C++支持
Java程序不需要显式地关心内存释放,而C/C++需要
49.在多线程中不加限制的随意访问非static局部变量不会导致运算结果出错
在多线程中不加限制的随意访问非static全局变量可能会导致运算结果出错
在多线程中不加限制的随意访问static局部变量不会导致运算结果出错
在多线程中不加限制的随意访问static全局变量可能会导致运算结果出错
50.关于类的权限:
类的对象只能访问该类的共有成员
普通函数不能直接访问的公有成员,必须通过对象访问
一个类可以将另一个类的对象作为成员
51.静态数据成员:
引用静态数据成员时,要在静态数据成员名前加<类名>和作用域符号
说明静态数据成员时前边要加关键字static来修饰
静态数据成员在类体外进行初始化
52.const char *ptr
指向字符常量的指针;
指向字符串常量的指针;
53.内部静态类的可见性与存在性不一致
54.关于私有访问控制符 private 修饰的成员变量只能被该类自身所访问和修改
55.do-while 循环体至少要执行一次
56.C中函数的定义不可以嵌套,但函数的调用可以嵌套
57.对于protected成员:
从派生类继承的子类里可以访问基类的protected成员
派生类可以定义一个同名的非protected成员
派生类可以访问基类对象的公有protected成员
58.C++11中的容器:
这里写图片描述
这里写图片描述
59.纯虚函数的正确声明virtual void print()=0;
60.在下列排序算法中,哪几个算法的时间复杂度与初始排序无关()堆排序归并排序 选择排序
61.C++的虚函数必须是类的一个成员,而不允许是类的友元。
62.调用一成员函数时, 使用动态联编的情况是通过指针或引用调用一虚函数
63.关于makefile:
makefile文件保存了编译器和连接器的参数选项
主要包含了五个东西:显式规则、隐晦规则、变量定义、文件指示和注释
默认的情况下,make命令会在当前目录下按顺序找寻文件名为“GNUmakefile”、“makefile”、“Makefile”的文件, 找到了解释这个文件
64.关于虚函数:
在成员函数声明的前面加上virtual修饰,就可把该函数声明为虚函数
虚函数可以是另一个类的友元函数,但不能是静态成员函数
基类中说明的纯虚函数在其任何需要实例化的派生类中都必须实现
65 cdecl调用转换支持可变长度参数
66.C++中,能作为函数重载判断依据的是?参数类型 Const 参数个数
sizeof操作符和strlen()函数的使用:
sizeof操作符:
①对于指针变量,sizeof操作符返回这个指针占的空间,一般为4个字节,也就是sizeof在编译时计算缓冲区的长度;
②对于数组,sizeof返回这个数组所有元素占的空间,但是字符串后面还有一个结束标志\n,sizeof这个必须算进去。
strlen()函数
strlen()函数不区分指针和数组,就读到\0为止返回长度,strlen()是不把\0计入字符串的长度,但必须注意,strlen()的参数只能是以\0结束的字符串;
两者之间的根本性不同:sizeof是操作符,操作时可以不用带括号,而strlen()是一个函数,必须要进行一次函数调用
sizeof是在编译时就计算出大小,而strlen()是在程序运行时才能计算出大小。

1.函数是可以[New一个对象的时候要根据虚函数函数体来填虚表;而内联函数没有函数体,只是在预编译阶段展开]内联的,这样就可以减少函数调用的开销,提高效率(错误) 2. 一个类里可以同时存在[同一个类里无论什么函数函数名和参数完全一样]参数和函数名都相同的虚函数与静态函数(错误) 3. 父类的析构函数是非虚的,但是子类的析构函数是虚的,delete子类指针(指向该子类对象)[特殊情况,参见题5],会调用父类的析构函数(正确)//任何情况下删除子类都会调用到父类的析构函数 4.对于下面的类CA,sizeof(CA) = _B_: A. 4 B. 8 C. 12 D. 16 class CA { public: CA(); virtual ~CA(); //因为有虚函数,所以会有4个字节的虚表指针 private: int m_iTime; //成员变量4个字节 public: int GetTime(); int SetTime(int iTime); }; 5.下面这段程序,打印结果是_A_: A. 1 B. 2 C. 3 D. 以上都对 int g_iCount = 0; class CParent { public: CParent() {} ~CParent() {g_iCount += 1;} }; class CSon : public CParent { public: CSon() {} ~CSon() {g_iCount += 2;} }; main() { CParent* p = new CSon(); delete p[由于p被声明成父类指针,并且父类和子类的析构函数都非虚,因此delete操作只能根据p指针声明的类型来调用父类的析构函数]; std::cout << g_iCount << std::endl; } 6.请问下面这段程序的输出结果是_A_: A. 2,1, B. 2,2, C. 1,1, D. 1,2, class CParent { public: CParent() {} virtual ~CParent() {} public: virtual void Print() { std::cout << "1,"; }; }; class CSon : public CParent { public: CSon() {}; virtual ~CSon() {}; public: void Print() { std::cout << "2,"; }; }; void Test1(CParent& oParent[这里是引用了一个外部对象,该对象的虚表会发生变化]) {oParent.Print();} void Test2(CParent oParent[这里会在栈空间内重新构造一个CParent类的对象,如果传入实参的类型与CParent同则虚表会发生变化]) {oParent.Print();} main() { CSon * p = new CSon(); Test1(*p); //这里只是一个引用 Test2(*p); //这里会在栈空间重新构造Cparent类对象 delete p; } 7.请问下面这段程序的输出结果是_D_: A. 2,1, B. 2,2, C. 1,1, D. 1,2, class CParent { public: CParent() {} virtual ~CParent() {} public: void Print(){ std::cout << "1," ; }; }; class CSon : public CParent { public: CSon() {} virtual ~CSon() {} public: void Print(){ std::cout << "2,"; }; }; main() { CSon oSon; CParent * pParent = &oSon; CSon * pSon = &oSon; pParent->Print(); pSon->Print();[由于父类和子类的Print函数都非虚,所以根据指针类型决定调用关系] } 8.请问下面这段程序的输出结果是_C_: A. 2,1, B. 2,2, C. 1,2, D. 1,1, class CParent { public: CParent() {Print();} virtual ~CParent() {} public: virtual void Print(){ std::cout << "1,"; } }; class CSon : public CParent { public: CSon() {Print();} virtual ~CSon() {} public: void Print(){ std::cout << "2,"; } }; main() { CParent * pParent = new CSon()[类的构造过程遵循压栈原则,构造过程中虚表尚未建立成功,是静态调用虚函数]; delete pParent; } 9.请问下面这段程序的输出结果是_D_: A. 2,2, B. 2, C. 输出结果确定 D. 以上都对 class CParent { public: CParent() {Print();[构造子类对象时调用到父类的构造函数,但父类的Print函数是纯虚的,没有实现,所以这里的调用成功,编译会出错]} virtual ~CParent() {} public: virtual void Print() = 0; }; class CSon : public CParent { public: CSon() {Print();} virtual ~CSon() {} public: void Print() { std::cout << "2,"; }; }; main() { CParent * pParent = new CSon(); delete pParent; } 10.请仔细阅读以下程序: class Base { public: virtual bool operator == (int iValue) { std::cout << "I am Base class !" << std::endl; return true; } virtual ~Base(){} }; class Derive: public Base { public: virtual bool operator == (int iValue) { std::cout << "I am Derive class !" << std::endl; return true; } virtual ~Derive(){} }; int main() { Derive derive; Base* pBase = &derive; Derive* pDerive = &derive; *pBase == 0; *pDerive == 0;[重载操作符声明为virtual使操作符产生多态性] return 0; } 程序的输出结果是_B_: A、I am Base class ! I am base class ! B、I am Derive class ! I am Derive class ! C、I am base class ! I am Derive class ! D、I am Derive class ! I am Base class !
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值