备战秋招 | 笔试强训13

一、选择题

1、下面叙述不正确的是()

A. 派生类一般都用公有派生

B. 对基类成员的访问必须是无二义性的

C. 赋值兼容规则也适用于多重继承的组合

D. 父类的公有成员在派生类中仍然是公有的

2、下面 C++ 程序的运行结果是()

#include <iostream>
using namespace std;
class parent 
{
    int i;
protected:
    int x;
public:
    parent() 
    { 
        x = 0; 
        i = 0; 
    }
    void change() 
    { 
        x++; 
        i++; 
    }
    void display();
};
class son :public parent 
{
public:
    void modify();
};
void parent::display() 
{
    cout << "x=" << x << endl;
}
void son::modify() 
{
    x++;
}
int main() 
{
    son A;
    parent B;
    A.display();
    A.change();
    A.modify();
    A.display();
    B.change();
    B.display();
    return 0;
}

A. x=1 x=0 x=2

B. x=2 x=0 x=1

C. x=0 x=2 x=1

D. x=0 x=1 x=2

3、关于虚函数的描述正确的是()

A. 派生类的虚函数与基类的虚函数具有不同的参数个数和类型

B. 内联函数不能是虚函数

C. 派生类必须重新定义基类的虚函数

D. 虚函数可以是一个static型的函数

4、当一个类对象的生命周期结束后,关于调用析构函数的描述正确的是()

A. 如果派生类没有定义析构函数,则只调用基类的析构函数

B. 如果基类没有定义析构函数,则只调用派生类的析构函数

C. 先调用派生类的析构函数,后调用基类的析构函数

D. 先调用基类的析构函数,后调用派生类的析构函数

5、以下关于纯虚函数的说法,正确的是()

A. 声明纯虚函数的类不能实例化

B. 声明纯虚函数的类成虚基类

C. 子类必须实现基类的

D. 纯虚函数必须是空函数

6、下列描述,正确的一共有多少个()

1)const char *p,这是一个常量指针,p的值不可修改

2)在64位机上,char *p= “abcdefghijk”; sizeof(p)大小为12

3)inline会检查函数参数,所以调用开销显著大于宏 4)重载是编译时确定的,虚函数是运行时绑定的

A. 1

B. 2

C. 3

D. 4

7、C++将父类的析构函数定义为虚函数,下列正确的是哪个()

A. 释放父类指针时能正确释放子类对象

B. 释放子类指针时能正确释放父类对象

C. 这样做是错误的

D. 以上全错

8、下列关于多态性说法不正确的是( )

A. 多态性是指同名函数对应多种不同的实现

B. 重载方式仅有函数重载

C. 重载方式包含函数重载和运算符重载

D. 多态性表现为静态和动态两种方式

9、分析一下这段程序的输出

#include<iostream>
using namespace std;
class B
{
public:
     B()
    {
        cout << "default constructor" << " ";
    }
    ~B()
    {
        cout << "destructed" << " ";
    }
    B(int i): data(i)
    {
        cout << "constructed by parameter" << data << " ";
    }
private: 
    int data;
};
B Play( B b)
{
    return b;
}
int main(int argc, char *argv[])
{
    B temp = Play(5);
    return 0;
}

A. constructed by parameter5 destructed destructed

B. constructed by parameter5 destructed

C. default constructor" constructed by parameter5 destructed

D. default constructor" constructed by parameter5 destructed destructed

10、求输出结果

using namespace std;
class A
{
public:
    virtual void print()
    {
        cout << "A::print()" << "\n";
    }
};
class B: public A
{
public: 
    virtual void print()
    {
        cout << "B::print()" << "\n";
    }
};
class C: public A
{
public: 
    virtual void print()
    {
        cout << "C::print()" << "\n";
    }
};
void print(A a)
{
    a.print();
}
int main()
{
    A a, *aa, *ab, *ac;
    B b;
    C c;
    aa = &a;
    ab = &b;
    ac = &c;
    a.print();
    b.print();
    c.print();
    aa->print();
    ab->print();
    ac->print();
    print(a);
    print(b);
    print(c);
    return 0;
}

A. C::print() B::print() A::print() A::print() B::print() C::print() A::print() A::print() A::print()

B. A::print() B::print() C::print() A::print() B::print() C::print() A::print() A::print() A::print()

C. A::print() B::print() C::print() A::print() B::print() C::print() B::print() B::print() B::print()

D. C::print() B::print() A::print() A::print() B::print() C::print() C::print() C::print() C::print()

二、编程题

1、参数解析  题目链接

2、跳石板   题目链接

 三、选择题题解

1、下面叙述不正确的是()

A. 派生类一般都用公有派生

B. 对基类成员的访问必须是无二义性的

C. 赋值兼容规则也适用于多重继承的组合

D. 父类的公有成员在派生类中仍然是公有的

正确答案:D

题解:

         派生类成员的继承方式取决于继承方式与成员修饰限定符较低的那个,对于class来说,若不显示定义继承方式则默认为private继承,若用struck定义类,默认继承方式为public继承;故D说法不正确,其他说法均正确;

2、下面 C++ 程序的运行结果是()

#include <iostream>
using namespace std;
class parent 
{
    int i;
protected:
    int x;
public:
    parent() 
    { 
        x = 0; 
        i = 0; 
    }
    void change() 
    { 
        x++; 
        i++; 
    }
    void display();
};
class son :public parent 
{
public:
    void modify();
};
void parent::display() 
{
    cout << "x=" << x << endl;
}
void son::modify() 
{
    x++;
}
int main() 
{
    son A;
    parent B;
    A.display();
    A.change();
    A.modify();
    A.display();
    B.change();
    B.display();
    return 0;
}

A. x=1 x=0 x=2

B. x=2 x=0 x=1

C. x=0 x=2 x=1

D. x=0 x=1 x=2

正确答案:C

题解:

         首先分析题目,题目中有两个类,一个是父类,一个是公有继承的子类,父类的对象中有两个成员变量,分别为x与i,其在构造函数中赋值为0;我们再看main函数里,分别构造了父类与子类,子类构造时首先会调用父类对象的构造函数,初始化父类对象的那一部分,因此对象A与B中的 x 与 i 均为0;A.display();首先打印了子类对象A中的x = 0;此时可以排除A、B这两个选项;接着,执行A.change();此时A类对象中的 x与 i 分别+1;再执行A.modify();此时A类对象中的x又+1;接着再次打印A对象中的x=2;排除D选项,此时已经可以选C了;我们继续往后看,接着执行了B.change();此时对B对象中的x与i分别+1;再次打印B对象中的x,输出x=1;

3、关于虚函数的描述正确的是()

A. 派生类的虚函数与基类的虚函数具有不同的参数个数和类型

B. 内联函数不能是虚函数

C. 派生类必须重新定义基类的虚函数

D. 虚函数可以是一个static型的函数

正确答案:B

题解:

         A选项,表达不明确且错误,当派生类的虚函数要被重写时,其虚函数的参数类型,参数个数,函数名,返回值都要相同,不然无法完成重写(除了协变与析构函数这两个例外);B选项,内联函数不可能是虚函数,因此内联函数没有地址,而虚函数的地址要放进虚表中的;C选项,派生类只要不重写虚函数就可可以不用重新定义虚函数;D选项,虚函数不可能为静态成员函数,因此虚函数的调用需要this指针,而静态成员函数没有this指针;

4、当一个类对象的生命周期结束后,关于调用析构函数的描述正确的是()

A. 如果派生类没有定义析构函数,则只调用基类的析构函数

B. 如果基类没有定义析构函数,则只调用派生类的析构函数

C. 先调用派生类的析构函数,后调用基类的析构函数

D. 先调用基类的析构函数,后调用派生类的析构函数

正确答案:C

题解:

         一个类若不显式定义出析构函数,编译器会为这个类生成一个默认的析构函数,而一个拥有继承体系的类,在定义时,会先调用父类构造,然后调用子类构造,而析构的顺序正好相反,先调用子类的析构函数,再调用父类的析构函数;因此答案选C;

5、以下关于纯虚函数的说法,正确的是()

A. 声明纯虚函数的类不能实例化

B. 声明纯虚函数的类成虚基类

C. 子类必须实现基类的虚函数

D. 纯虚函数必须是空函数

正确答案:A

题解:

         声明为纯虚函数的类不能实例化,是一种抽象类,A正确;虚基类常常出现在菱形继承的情况中,与纯虚函数并无关系,B选项错误;子类如果不重写父类的虚函数,可不用实现父类的虚函数,C错误;纯虚函数可以有自己的函数体,只是没有意义,故D错误;

6、下列描述,正确的一共有多少个()

1)const char *p,这是一个常量指针,p的值不可修改

2)在64位机上,char *p= “abcdefghijk”; sizeof(p)大小为12

3)inline会检查函数参数,所以调用开销显著大于宏

4)重载是编译时确定的,虚函数是运行时绑定的

A. 1

B. 2

C. 3

D. 4

正确答案:A

题解:

         1)是一个常量指针,p的值可以改变,其指向的内容不可修改,故错误;2)指针在32位机器上大小为固定的4字节,在64位机器下固定大小为8字节;3)宏与内联函数都是在调用时展开,效率并无二异;4)描述正确;

7、C++将父类的析构函数定义为虚函数,下列正确的是哪个()

A. 释放父类指针时能正确释放子类对象

B. 释放子类指针时能正确释放父类对象

C. 这样做是错误的

D. 以上全错

正确答案:A

题解:

         本题主要考察析构函数的多态,当我们new一个子类对象时,将父类的析构函数设置为虚函数,这样释放父类指针时,满足多态场景;(其实博主觉得题目认为有些问题,当我们释放子类指针时,也能正确子类中父类的那一部分,如果非要纠错就是说这里的父类对象描述的不够准确);

8、下列关于多态性说法不正确的是( )

A. 多态性是指同名函数对应多种不同的实现

B. 重载方式仅有函数重载

C. 重载方式包含函数重载和运算符重载

D. 多态性表现为静态和动态两种方式

正确答案:B

题解:

         除了函数重载以外还有运算符重载,故B错误;

9、分析一下这段程序的输出

#include<iostream>
using namespace std;
class B
{
public:
     B()
    {
        cout << "default constructor" << " ";
    }
    ~B()
    {
        cout << "destructed" << " ";
    }
    B(int i): data(i)
    {
        cout << "constructed by parameter" << data << " ";
    }
private: 
    int data;
};
B Play( B b)
{
    return b;
}
int main(int argc, char *argv[])
{
    B temp = Play(5);
    return 0;
}

A. constructed by parameter5 destructed destructed

B. constructed by parameter5 destructed

C. default constructor" constructed by parameter5 destructed

D. default constructor" constructed by parameter5 destructed destructed

正确答案:A

 题解:

        这题设计编译器的优化,当我们传入5时,编译器直接用5帮我们构造出形参,因此这里调用一次单参构造函数,然后返回时,这里也有一次优化,这里返回时直接把形参b拷贝构造给temp,同时调用析构函数将形参b析构了,然后主函数结束,temp也被析构一次,故选A

10、求输出结果

using namespace std;
class A
{
public:
    virtual void print()
    {
        cout << "A::print()" << "\n";
    }
};
class B: public A
{
public: 
    virtual void print()
    {
        cout << "B::print()" << "\n";
    }
};
class C: public A
{
public: 
    virtual void print()
    {
        cout << "C::print()" << "\n";
    }
};
void print(A a)
{
    a.print();
}
int main()
{
    A a, *aa, *ab, *ac;
    B b;
    C c;
    aa = &a;
    ab = &b;
    ac = &c;
    a.print();
    b.print();
    c.print();
    aa->print();
    ab->print();
    ac->print();
    print(a);
    print(b);
    print(c);
    return 0;
}

A. C::print() B::print() A::print() A::print() B::print() C::print() A::print() A::print() A::print()

B. A::print() B::print() C::print() A::print() B::print() C::print() A::print() A::print() A::print()

C. A::print() B::print() C::print() A::print() B::print() C::print() B::print() B::print() B::print()

D. C::print() B::print() A::print() A::print() B::print() C::print() C::print() C::print() C::print()

正确答案:B

题解:

        首先用a、b、c三个类型对象调用他们的print函数,分别打印a、b、c的print函数;再用父类的指针调用虚函数,这里严格卡住多态的两个调节,父类的指针或引用调用,以及虚函数的重写,故形成多态,分别调用a、b、c的print函数,最后分别用a对象调用print函数,并不会引起多态,故打印三个a;

四、编程题题解

1、参数解析

思路:首先我们要读懂题目,其中当出现双引号时,我们就不能以空格作为分隔符,当在双引号外时,以空格分割参数;

#include <iostream>
#include <vector>
#include <string>
using namespace std;

int main() 
{
    string str;
    vector<string> ret;
    getline(cin, str);
    string tmp;
    // 判断是否在双引号内
    bool flag = false;
    for(int i = 0; i < str.size(); i++)
    {
        if(str[i] == '"')
        {
            flag = !flag;
        }
        else if(str[i] == ' ' && flag == false)
        {
            ret.push_back(tmp);
            tmp.clear();
        }
        else 
        {
            tmp += str[i];
        }
    }
    // 查看最后一个字符串是否录入
    if(tmp != "")
        ret.push_back(tmp);
    // 输出答案
    cout << ret.size() << endl;
    for(auto& str : ret)
    {
        cout << str << endl;
    }
    return 0;
}

2、跳石板

思路:本题主要考察动态规划,具体题解如下图;

#include <iostream>
#include <vector>
#include <limits.h>
#include <math.h>
using namespace std;

void get_nums(int n, vector<int>& nums)
{
    // 提高找因子的效率
    for(int i = 2; i <= sqrt(n); i++)
    {
        if(n % i == 0)
        {
            nums.push_back(i);
            if((n / i) != i)
            {
                nums.push_back(n / i);
            }
        }
    }
}

int jump_stone(int n, int m)
{
    // 初始化dp数组,INT_MAX代表到达不了的石板
    // (下标从0开始,所以多开了一个空间)
    vector<int> dp(m + 1, INT_MAX);
    // 初始化起点
    dp[n] = 0;
    for(int i = n; i < m; i++)
    {
        // 当前下标无法到达
        if(dp[i] == INT_MAX)
            continue;
        // 保存因子
        vector<int> nums;
        get_nums(i, nums);
        // 遍历因子更新dp数组
        for(int j = 0; j < nums.size(); j++)
        {
            // 可以更新dp数组
            if(nums[j] + i <= m)
            {
                // 取最小步数
                dp[nums[j] + i] = min(dp[nums[j] + i], dp[i] + 1);
            }
        }
    }
    // 检测是否无法到达
    return dp[m] == INT_MAX ? -1 : dp[m];
}

int main() 
{
    int n, m;
    cin >> n >> m;
    int min_step = 0;
    min_step = jump_stone(n, m);
    cout << min_step << endl;
    return 0;
}

猜你喜欢

转载自blog.csdn.net/Nice_W/article/details/131901835