技术面试(C++)

来源:互联网 发布:数据挖掘学习 编辑:程序博客网 时间:2024/05/19 15:18

面试中也曾经遇到过一些语法类的问题,大部分能够解决,但是也有很多做不出来,今天开始进行C++语法的总结,尤其因为我完全不用Java,所以,C++语法就显得愈加重要,开始阶段可能是一些我已经掌握的表面的知识,之后就是一些比较深层次或者偏门的知识,希望能一天一道,20天左右总结一遍。。


另外,如果各位看到我blog的同学或者前辈觉得我写的有啥错误,也请不吝赐教,因为我C++用的时间并不长,很多东西理解的并不好。。


NO.1 虚函数(virtual function)

这个应该算是我平时可以掌握的知识,因为自己写代码的时候也可能会涉及,就举一个最简单的例子吧,类定义如下所示:

#define NAME_SIZE 50class Person {        int id;     // all members are private by default        char name[NAME_SIZE];            public:        void aboutMe() {            cout << "I am a person.";        }};class Student: public Person {    public:        void aboutMe() {            cout << "I am a student.";        }};

如果运行:

    Student* p = new Student();    p->aboutMe();

输出的是"I am a Student",但是,如果运行:

    Person* p = new Student();    p->aboutMe();

输出的是"I am a Person",这是因为aboutMe()这个函数是在编译的时候解析的,这种机制是static - binding

如果把aboutMe()写作虚函数,则机制是dynamic - binding,此时输出的是Student class的aboutMe(),即输出"I am a student.",代码如下:

#define NAME_SIZE 50class Person {        int id;     // all members are private by default        char name[NAME_SIZE];            public:        virtual void aboutMe() {            cout << "I am a person.";        }};class Student: public Person {    public:        virtual void aboutMe() {            cout << "I am a student.";        }};

还有一个概念就是虚函数表(vtable),因为这个确实没有学过,所以不深究,但是也不能一问三不知,所以大概说一下vtable的功能:

如果一个类中的某一个函数被声明为虚函数,则就会建立虚函数表用来保存该类的虚函数的地址。同时编译器也会指定一个隐含的vptr来指向这个vtable。

NO.2 纯虚函数(pure virtual function)


NO.3 New的过程

这道题是我朋友面Akuna Capital的一道电面题,如果是我的话,我的答案如下:

int* p = new int[5];

首先获得需要分配空间的大小,之后new操作符会在Heap中分配这么大的内存,然后返回内存的守地址,保存在栈中。

当然,这题我也不确定是不是面试官要的答案,听朋友讲他说面试官对他的答案不是特别满意。。

NO.4 Override & Overwrite

其实这个问题我现在的理解依然相当模糊,很难说出有啥特别的不同来。。。这个问题将来还得不断的去加深理解

先上程序:

#include <iostream>using namespace std;class CBase {    public:        virtual void A(int val) {            cout << "CBase::A()" << endl;        }                void B(int val) {            cout << "CBase::B()" << endl;        }                void C(int val) {            cout << "CBase::C()" << endl;        }};class CDrive: public CBase {    public:        virtual void A(int val) {            cout << "CDrive::A()" << endl;      // override        }                void B(int val) {            cout << "CDrive::B()" << endl;      // overwirte        }                void C(int val) {            cout << "CDrive::C()" << endl;      // overwrite        }};int main(int argc, char** argv) {    CDrive child;    CBase* father = new CDrive();    child.A(1);    father->A(1);    cout << endl;        child.B(1);    father->B(1);    cout << endl;        child.C(1);    father->C(1);        return 0;}
这个程序大概说明了规则:Override是同名同参虚函数,overwrite则是同名同参函数或者同名非同参的函数及虚函数。输出结果如下图所示:

CDrive::A()CDrive::A()CDrive::B()CBase::B()CDrive::C()CBase::C()

这个题还不算完,果断时间看看书还需要继续改进。

NO.5 static & extern 


NO.6 deep copy & shallow copy

这个题我同学面JDSU时曾经遇到过,而且在Cracking the Coding Interview这本书里面也有讲解。。。在自己写类的拷贝构造函数的时候是需要注意的。。

下面的就是一个我写的shallow copy constructor的例子,并不难理解:

// shallow copy constructorshallow_copy(const shallow_copy& item) {    a = itme.a;}

浅拷贝就是在a2 = a1后,他俩指向同一片空间,所以当a1释放后,a2就是指向空,下面举一个deep copy constuctor的例子:

// deep copy constructordeep_copy(const deep_copy& item) {    a = new char[strlen(item.a)+1];    strcpy(a, item.a);}

NO.7 Friend class & Friend function


NO.8 Virtual Destructor

本题在我去SevOne面试的时候考过。

#include <iostream>using namespace std;class Base {    public:        Base() {            cout << "Base construct" << endl;        }        ~Base() {            cout << "Base destruct" << endl;        }};class Derive: public Base {    public:        Derive() {            cout << "Derive construct" << endl;        }        ~Derive() {            cout << "Derive destruct" << endl;        }};int main(int argc, char** argv) {    Base* b = new Derive();    delete b;}
如果程序按上面的写法的话,运行结果为:

Base constructDerive constructBase destruct
从这个就可以看出调用的是Base指针指向的destructor,然而Derive的空间并没有得到释放。。

所以此时应该在Base的析构函数前加上virtual,则变为:

#include <iostream>using namespace std;class Base {    public:        Base() {            cout << "Base construct" << endl;        }        virtual ~Base() {            cout << "Base destruct" << endl;        }};class Derive: public Base {    public:        Derive() {            cout << "Derive construct" << endl;        }        ~Derive() {            cout << "Derive destruct" << endl;        }};int main(int argc, char** argv) {    Base* b = new Derive();    delete b;}
运行结果为:

Base constructDerive constructDerive destructBase destruct
这就是使用virtual destructor的原因:希望派生类的析构函数被调用

NO.9 Stack & Heap

这个题也是在SevOne被考过,我答得也是一般。。













0 0