本节博客是对阅读剑指offer后的笔记归纳总结,有需要借鉴即可。
目录
- 1.p21-p25内容概要
- 2.询问语法概念
- 常考:CPP关键字理解
- 举例:sizeof空类
- 3.分析代码
- 举例:类中拷贝构造的无限递归问题
- 4.写代码
- 常考点:类内成员函数、迭代器
- 举例:string模拟实现的赋值运算重载
- 5.总结
1.p21-p25内容概要
面试官对于语言的考察,主要有三种考察形式
- 1.询问语法概念
- 2.分析代码
- 3.写代码
下面来依次进行举例(以cpp为例)并分析,对书中内容进行总结和提炼。
2.询问语法概念
常考:CPP关键字理解
举例:sizeof空类
问:定义一个空类型,里面没有任何函数和变量,其sizeof大小是多少?
答:非0,具体是多少取决于编译器。原因在于至少给一个字节标识该结构体的存在,从而能够去使用。
问:在该空类型中添加相对于的构造函数和析构函数,sizeof该类型是多大?为什么?
答:依旧是非0,原因在于构造函数和析构函数用到的是该类对象的地址,并且类中的函数是存放在内存的公共代码区的,并没有真的放在类对象中。如下图:
3.分析代码
举例:类中拷贝构造的无限递归问题
问:下面代码是否可以进行编译?其结果是什么?
class A
{
private:
int value;
piblic:
A(int n){value = n;}
A(A other) {value = other.value;}
void Print(){std::cout << value << std:endl;}
};
int _tmain(int arge,_TCHAR* argv[])
{
A a = 10;
A b = a;
b.Print();
return 0;
}
其实这个地方我感觉要看编译器怎么看待A(A other) {value = other.value;}该函数了。我自己在vs2022的环境下去测上面代码结果是10
如果编译器将其视为拷贝构造函数,那么编译是可以编过的,但是会陷入无限递归模式。
这是因为CPP语法规定值传参要调用拷贝构造进行拷贝。所以把a要先传给other就得调用拷贝构造,就会陷入无限递归模式。
如果编译器将其视为一般的构造函数重载,编译可以编过并且运行结果是10
这是因为编译器会因为没有拷贝构造而自动提供一份拷贝构造,虽然编译器提供的这个拷贝构造是浅拷贝,但在这个地方也足够用。
4.写代码
常考点:类内成员函数、迭代器
举例:string模拟实现的赋值运算重载
如下图为模拟string的类声明,请补充其赋值运算重载
下面直接给出一般答案,请思考其中的问题:
下面是对上面图片中的问题进行解答:
- 1.返回类型string&:
- 引用提高代码效率,引用不存在值拷贝调用拷贝构造问题
- 返回string支持连续赋值,若为void则连续赋值会报错
- 2.参数类型const string&
- 引用提高代码效率
- const限制str在函数内被修改
- 3.if必要性
- 具有必要性。
- 可以防自赋值,提高代码效率
- 在当前代码下,若无if,自赋值delete会把str和其本身全部delete,会变成空
- 4.delete具有必要性
- 防止内存泄漏长期影响服务器导致崩溃问题
- 减少资源浪费
然而,虽然上面代码基本凑合,但是还有一个小问题,在特定场景下会出现崩溃。
异常安全性问题:
当内存不足时,new char会抛异常,从而终止程序。
在上面代码中,会先删后创,如果发生new抛异常,会造成原string内容丢失。
解决方案:
- 方案1:将上面代码改为先创建新内容,再删除旧内容
- 方案2:使用现代写法,即先创建一个临时string变量,再将其内容与*this进行交换
下面是现代写法示例:
实际上,这种现代写法本质就是一种代码复用。
5.总结
本文主要是用三个例子讲了面试对语法的三种考察形式。
我感觉《剑指offer》这三个例子举得挺好,可以好好思考一波。
EOF