C++面试题4

第4课 - 外企笔试题精选二

  1. 下面代码是否有错?如果有错,错在哪里?

struct Test

{

         Test() {}

         Test(int i) {}

         void func() {}

};

int main()

{

         Test t1(1);

         Test t2();

         t1.func();

         t2.func();

}

分析:改错是工作能力的体现。

Test t2()是个函数声明,不是我们期望的t2对象,函数的声明可以发生在任何地方,可以在main函数内部,也可以在函数外部。这样在后面的语句t2.func();就会出问题。

         main()函数的类型是int,但是没有返回值。这种语句在C语言中是合法的,在C++语言中则是不合法的,但是由于C++对C语言的兼容性,在运行时不会出错。我们在做产品代码时,main()没有返回值就会出错。

 

  1. 下面的代码输出是什么?为什么?

class Test

{

         int m_i;

         int m_j;

public:

         Test(int v):m_j(v),m_i(m_j)   //初始化列表

         {

}

int getI()

{

         return m_i;

}

Int getJ()

{

         return m_j;

}

};

int main()

{

         Test t1(1);   //t1对象

         Test t2(2);   //t2对象

         cout<<t1.get()<<” ”t1.getJ()<<endl;

         cout<<t2.get()<<” ”t2.getJ()<<endl;

         return 0;

}

输出:213458607 1

           323564643 2

分析:这段程序用到了初始化列表,初始化列表的初始化顺序不是按照我们书写的顺序进行初始化的,而是按照成员变量的声明顺序进行的初始化。先初始化m_i,此时m_j中是随机数,所以出现乱码,后初始化m_j,m_j的值变成1和2。

         成员函数的初始化顺序只有它们声明的顺序相关,与初始化列表的顺序无关。

        

  1. 下面的代码输出是什么?为什么?

class Test

{

         int m_i;

         int m_j;

public:

         Test()

         {

                   cout<<”Test()”<<endl;

}

Test(int v)

{

         cout<<”Test(int v)”<<endl;

}

~Test()

{

         cout<<”~Test()”<<endl;

}

};

Test Play(Test t)

{

         return t;

}

int main()

{

         Test t = Play(5);

         return 0;

}

运行结果: Test(int v)

                      ~Test()

                      ~Test()

分析:这里考查C++编译器的智能试探,直接调用5不是Test类型,就可以间接的使用。Test t = Play(5)等价于Test t = Play(Test(5)),首先运行Test(5),运行构造函数Test(int v)

,输出结果为Test(int v);之后运行Test Play(Test t),将t的值复制给返回值空间,这样我们得到一个返回值对象。在Test Play(Test t)中的t运行完成之后,遇到return t,触发析构函数,输出:~Test(),在主函数中的t运行完成之后,遇到return 0,再次触发析构函数,输出:~Test()。

 

  1. Which virtual function re-declarations of the Derived class are correct?
  2. Base* Base::copy(Base*);

Base* Derived::copy(Derived*);

  1. Base* Base::copy(Base*);

Derived * Derived::copy(Derived*);

  1. int Base::cout();

int Derived::cout();

  1. void Base::func(Base*) const;

void Derived::func(Base*);

答案选:C

分析:考查多态。多态发生在基类与派生类之间,基类与派生类的函数必须完全一样。C选项满足要求,D选项中,类的const函数,也算是成员函数的一个方面,D也不满足完全一致的函数要求。

 

  1. 下面的程序输出是什么?为什么?

class Base

{

public:

         virtual void func()

         {

                   cout<<”Base::func()”<<endl;

}

};

class Child:public Base

{

public:

         void func()

         {

                   cout<<”Child::func()”<<endl;  //子类的函数形式与父类一样,一定会发生多态。

}

};

int main()

{

         Base* pb = new Base(); //基类的指针指向基类的对象

         pb->func();  //输出Base::func()

         Child* pc = (Child*)pb; //产品级的代码中是不允许这样做的,子类的指针,指向父类的

                                                  //函数

         pc->func();   //由于虚函数表指针的存在,同样输出Base::func()

         delete pc;

         pb = new Child();  //父类指针,指向子类对象

         pb->func();      //调用子类函数

         pc = (Child*)pb;  //子类指针指向子类对象

         pc->func();      //子类指针调用子类对象

}

运行结果:

         Base::func()

         Base::func()

         Child::func()

         Child::func()

分析:考查多态,多态是设计模式中常用的理论。本题考查了虚函数的实现原理考察了编译器在编译过程中是如何实现动态衍变的。对于有虚函数的类(Base),虚函数指针指向函数的地址(虚函数表),也就是本题中func()的地址。在Child类中,也存在一个我们看不见的虚函数指针vptr,指向func()的地址,指向的过程是vptr指向pb中的虚函数指针,接着指向虚函数表中的func()函数,再指向func()函数的地址。虽然使用的是子类的指针,但是却和使用父类指针的调用过程是一样的。如果父类中的函数不是虚函数,这样写就会崩溃。

 

  1. A C++ developer wants to handle a static _cast<char*>() operation for the String class shown below. Which of the following options are valid declarations that will accomplish this task?

class String

{

public:

         //…

         //delaration goes here

};

  1. char* operator char* ();
  2. operation char* ();
  3. char* operator ();
  4. char* operator String ();

答案选:C

分析:题目希望将一个字符串类强制转换为一个字符指针,这里需要使用类型转换函数,具体的语法结构是:

operator char*()

{

           return NULL;

}

类型转换函数在工程中一般是不会使用的,容易造成紊乱。

 

  1. 以下两种情况:

(1)    new一个10个元素的数组

(2)    分10次new一个整型变量

哪个占用空间更大些?

  1. 1
  2. 2
  3. 一样多
  4. 无法确定

答案选:2

分析:new函数堆空间申请内存时,还会在申请空间之前申请一块空间,存放申请空间的信息,分开申请10次,申请的存放信息的空间也更多一些。

 

 

  1. 下面程序输出什么?

int main()

{

         int v[2][10] =    //可以看成v是一个有两个元素的数组,每个元素又含有10个元素

         {

                   {1,2,3,4,5,6,7,8,9,10},   //看成v[0]中的内容,*v指向v[0],**v指向v[0]中的第一//个元素

                   {11,12,13,14,15,16,17,18,19,20}  //看成v[1]中的内容

};  //v代表整个数组

int (*a)[8] = (int(*)[8])v; //一个数组指针,一个指向数组的指针,将v转换为含有8个元//素的数组指针

cout<<**a<<endl; //一个*指向指针所指的空间的内容,二维数组在空间中是按照一维//的方式去排列的,**a指向v[0]中的第一个元素,输出1

cout<<**(a+1)<<endl;  //a+1移动8个int,输出9

cout<<*(*a+1)<<endl;  //*a+1,表示第二个元素,输出2

cout<<*(a[0]+1)<<endl;  //等价上一条语句,输出2

cout<<*a[1]<<endl;  //第二个8的开始,输出9

return 0;

}

分析:考查数组指针,指针运算。

 

  1. 下面的程序输出是什么?为什么?

class Base

{

public:

         int a;

         Base() {a = 1;}

         void println(){cout<<a<<endl;;}

};

Class Child:public Base

{

public:

         int a;

         Child(){a = 2;}

};

int main()

{

         Child c;

         c.println(); //1

         cout<<c.a<<endl;  //2

}

分析:父类与子类中都有a,由于作用域的关系void println()只能看到自身的数值,无法看到子类中的数字。如果子类与父类有同名的成员变量,子类的成员变量将覆盖父类的成员变量。

 

  1. 用C/C++语言实现一个存储整型数据的栈数据结构,要求实现以下功能:

(1)    入栈操纵push

(2)    出栈操作pop

(3)    栈大小操作size

(4)    栈中最小元素min

#include <iostream>

#include <list>

using namespace std;

class IntStack

{

private:

    list<int> m_stack;

    list<int> m_cmax;

public:

    void push(int v);

    int pop();

    int top();

    int size();

    int max();

};

 

void IntStack::push(int v)

{

    m_stack.push_front(v);

    if( m_cmax.size() != 0 )

    {

        if( v > m_cmax.front() )

        {

            m_cmax.push_front(v);

        }

        else

        {

            m_cmax.push_front(m_cmax.front());

        }

    }

    else

    {

        m_cmax.push_front(v);

    }

}

int IntStack::pop()

{

    int ret = m_stack.front();

    m_stack.pop_front();

    m_cmax.pop_front();

    return ret;

}

int IntStack::top()

{

    return m_stack.front();

}

int IntStack::size()

{

    return m_stack.size();

}

int IntStack::max()

{

    return m_cmax.front();

}

int main()

{

    IntStack s;

    int array[] = {7, 2, 3, 1, 1, 4, 5};

    for(int i=0; i<sizeof(array)/sizeof(*array); i++)

    {

        s.push(array[i]);

    }

    while( s.size() )

    {

        cout<<s.top()<<endl;

        cout<<s.max()<<endl;

        s.pop();

        cout<<endl;

    }

}

 

  1. 编程实现二叉树的相等比较,当二叉树每个结点中的值对应相等时,二叉树相等,否则不相等。

二叉树每个结点由如下结构体表示:

struct BTreeNode

{

         int v;

         BTreeNode* left;

         BtreeNode* right;

};

         函数原型:

         Bool BTreeCompare(BtreeNode* b1, BtreeNode* b2);

 

#include <iostream>

#include <list>

 

using namespace std;

 

struct BTreeNode

{

    int v;

    BTreeNode* left;

    BTreeNode* right;

};

 

bool BTreeCompare(BTreeNode* b1, BTreeNode* b2)

{

    bool ret = false;

 

    if( b1 && b2 )

    {

        ret = (b1->v == b2->v) && BTreeCompare(b1->left, b2->left) && BTreeCompare(b1->right, b2->right);

    }

 

    if( !b1 && !b2 )

    {

        ret = true;

    }

 

    return ret;

}

 

bool BTreeCompareEx(BTreeNode* b1, BTreeNode* b2)

{

    bool ret = true;

    list<BTreeNode*> l1;

    list<BTreeNode*> l2;

 

    l1.push_back(b1);

    l2.push_back(b2);

 

    while( ret && l1.size() && l2.size() )

    {

        BTreeNode* n1 = l1.front();

        BTreeNode* n2 = l2.front();

 

        l1.pop_front();

        l2.pop_front();

 

        if( (n1 != NULL) && (n2 != NULL) )

        {

            ret = (n1->v == n2->v);

 

            l1.push_back(n1->left);

            l1.push_back(n1->right);

 

            l2.push_back(n2->left);

            l2.push_back(n2->right);

        }

        else

        if( (n1 == NULL) && (n2 != NULL) )

        {

            ret = false;

        }

        else

        if( (n1 != NULL) && (n2 == NULL) )

        {

            ret = false;

        }

    }

 

    return ret && (l1.size() == 0) && (l2.size() == 0);

}

 

int main()

{

    BTreeNode n1[10] = {0};

    BTreeNode n2[10] = {0};

 

    for(int i=0; i<10; i++)

    {

        n1[i].v = i;

        n2[i].v = i;

    }

 

    n1[0].left = &n1[1];

    n1[0].right = &n1[2];

    n1[1].left = &n1[3];

    n1[1].right = &n1[4];

    n1[2].left = &n1[5];

    n1[2].right = &n1[6];

    n1[3].left = &n1[7];

    n1[3].right = &n1[8];

    n1[4].left = &n1[9];

 

    n2[0].left = &n2[1];

    n2[0].right = &n2[2];

    n2[1].left = &n2[3];

    n2[1].right = &n2[4];

    n2[2].left = &n2[5];

    n2[2].right = &n2[6];

    n2[3].left = &n2[7];

    n2[3].right = &n2[8];

    n2[4].left = &n2[9];

 

    cout<<BTreeCompare(n1, n2)<<endl;

    cout<<BTreeCompareEx(n1, n2)<<endl;

}

posted @ 2019-08-12 19:05  free-锻炼身体  阅读(143)  评论(0编辑  收藏  举报