语言面试题
#include <iostream>
using namespace std;
class A
{
public:
A() : m_ival(0)
{
test();
}
virtual void func()
{
cout << m_ival << endl;
}
void test()
{
func();
}
public:
int m_ival;
};
class B : public A
{
public:
B()
{
test();
}
void func()
{
++ m_ival;
cout << m_ival << endl;
}
};
int main()
{
A* p = new B;
p->test();
delete p;
return 0;
}
问 1:分析下面的程序,给出运行结果
输出:
0
1
2
问 二 :在子类与父类构造函数中都调用test(), 那么编译器是怎么确定应该调用的哪个 func() 函数版本呢?
相关概念:
- 构造函数未结束前,虚函数表未初始化完成,因此不能发生多态
- 动态联编不等价于多态:
动态联编:编译原理中的概念
多 态:面向对象理论。 C++ 编译器在实现面向对象的多态时,使用动态联编的概念
发生了什么?
-
在构造 A 部分时:
- 在构造 A 部分时,回去构造 A 部分的虚函数表。在执行 A 的构造函数的函数体时,虚函数表是【完整】的
- 在 A 的构造函数中调用 Func(), 发生动态联编,查找虚函数表得到具体函数地址
- A 中的 Func 被调用
-
在构造 B 部分时:
- 在构造 B 部分时,【虚函数表被更新】
- 在 B 的构造函数中调用 Func(), 发生动态联编,查找虚函数表得到具体函数地址
- B 中的 Func 被调用
总结:
- 在构造函数中,调用虚函数不会发生多态,但虚函数是动态联编的
- 虚函数的调用,都是通过查找虚函数表完成的
问 三:上述的代码是否有其它问题?
- 问题 1, 未判断内存是否申请成功
-
问题 2
- A* p = new B; delete p;
- A 类指针 p 指向 B 类对象,在 delete 时,析构函数不是虚函数,因此,编译器就只会根据 p 的类型调用 A 类的析构函数, B 类的析构函数不会被调用!!!
要点
- 面试官需要的不只是“正确答案”
- 面试官会想要知道应试者的解题思路
- 面试官会从题中间“随机抓取”细节进行追问
- 面试官会把问题进行扩展(如:从语言扩展到编译器)
算法面试题
HR 问:编写代码将一个链表反转打印
面试者:需要思考的问题
- 这具体是一个什么样的链表(单链表?双向链表?循环链表)
- 链表中节点的数据是否允许改变
- 时间复杂度有没有要求
- 。。。
struct Node
{
int v;
struct Node* next;
};
void reversse_display_list(struct Node* list)
{
if( list )
{
reversse_display_list(list->next);
printf("%d ", list->v);
}
}
void reversse_display_list_stack(struct Node* list)
{
if( list )
{
LinkStack<int> stack;
while( list ) // O(n)
{
stack.push(list->v);
list = list->next;
}
while( stack.size() > 0 ) // O(n)
{
printf("%d ", stack.top());
stack.pop();
}
printf("\n");
}
}
struct Node* reverse_list(struct Node* list) // O(n)
{
if( list )
{
struct Node* guard = NULL;
struct Node* next = list->next;
while( next )
{
list->next = guard;
guard = list;
list = next;
next = list->next;
}
list->next = guard;
}
return list;
}
要点
- 面试不是笔试,面试考察的不只是技术
- 面试官需要全方位考察应试者(沟通,品质,态度)
- 面试中尽量与面试官交流,获取解题的有用信息
- 面试中尽量写出完整代码,而不是纸上谈兵的忽悠
- 。。。
发散性思维问题
不用加减乘除运算符做整数加法
面试者: 需要思考的问题
- 面试官想考察什么?
- 加法的底层本质是什么?
- 是否可以绕开 “+” 操作符的使用
- 。。。
int add_1(int a, int b)
{
int ret = 0;
asm volatile
(
"movl %%eax, %%ecx\n"
"addl %%ebx, %%ecx\n"
: "=c"(ret)
: "a"(a), "b"(b)
);
return ret;
}
int add_2(int a, int b)
{
int part = 0;
int carry = 0;
do
{
part = a ^ b;
carry = (a & b) << 1;
a = part;
b = carry;
} while( b != 0 );
return a;
}
要点
- 不同公司对人才的要求是不同的
- 一些公司会更看重应试者的可塑性
- 学习,分析,思考能力是工作中必备的(面试需要考察)
- 计算机系统底层原理的学习必不可少
- 。。。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。