目录
一、选择题
二、编程题
三、选择题题解
四、编程题题解
一、选择题
1、在公有派生的情况下,派生类中定义的成员函数只能访问原基类的()
A. 公有成员和私有成员
B. 私有成员和保护成员
C. 公有成员和保护成员
D. 私有成员,保护成员和公有成员
2、有如下C++代码:输出答案为
struct A
{
void foo(){printf("foo");}
virtual void bar(){printf("bar");}
A(){bar();}
};
struct B:A
{
void foo(){printf("b_foo");}
void bar(){printf("b_bar");}
};
int main()
{
A *p = new B;
p->foo();
p->bar();
return 0;
}
A. barfoob_bar
B. foobarb_bar
C. barfoob_foo
D. foobarb_fpp
3、关于抽象类和纯虚函数的描述中,错误的是
A. 纯虚函数的声明以“=0;”结束
B. 有纯虚函数的类叫抽象类,它不能用来定义对象
C. 抽象类的派生类如果不实现纯虚函数,它也是抽象类
D. 纯虚函数不能有函数体
4、以下程序输出结果是()
class A
{
public:
virtual void func(int val = 1)
{
std::cout<<"A->"<<val <<std::endl;}
virtual void test()
{
func();
}
};
class B : public A
{
public:
void func(int val=0)
{
std::cout<<"B->"<<val <<std::endl;
}
};
int main(int argc ,char* argv[])
{
B*p = new B;
p->test();
return 0;
}
A. A->0
B. B->1
C. A->1
D. B->0
5、下面程序的输出是()
class A
{
public:
void foo()
{
printf("1");
}
virtual void fun()
{
printf("2");
}
};
class B: public A
{
public:
void foo()
{
printf("3");
}
void fun()
{
printf("4");
}
};
int main(void)
{
A a;
B b;
A *p = &a;
p->foo();
p->fun();
p = &b;
p->foo();
p->fun();
A *ptr = (A *)&b;
ptr->foo();
ptr->fun();
return 0;
}
A. 121434
B. 121414
C. 121232
D. 123434
6、如果类B继承类A,A::x()被声明为虚函数,B::x()重载了A::x()方法,在下述语句中哪个x()方法会被调用()
B b;
b.x();
A. A::x()
B. B::x()
C. A::x() B::x()
D. B::x() A::x()
7、下面关于虚函数的描述,错误的是
A. 在成员函数声明的前面加上virtual修饰,就可把该函数声明为虚函数
B. 基类中说明了虚函数后,派生类中对应的函数也必须说明为虚函数
C. 虚函数可以是另一个类的友元函数,但不能是静态成员函数
D. 基类中说明的纯虚函数在其任何需要实例化的派生类中都必须实现
8、下列为纯虚函数的正确声明的是()
A. void virtual print()=0;
B. virtual void print()=0;
C. virtual void print(){};
D. virtual void print()\;
9、下面这段代码运行时会出现什么问题?
class A
{
public:
void f()
{
printf("A\n");
}
};
class B: public A
{
public:
virtual void f()
{
printf("B\n");
}
};
int main()
{
A *a = new B;
a->f();
delete a;
return 0;
}
A. 没有问题,输出B
B. 不符合预期的输出A
C. 程序不正确
D. 以上答案都不正确
10、下面这段代码会打印出什么?
class A
{
public:
A()
{
printf("A ");
}
~A()
{
printf("deA ");
}
};
class B
{
public:
B()
{
printf("B ");
}
~B()
{
printf("deB ");
}
};
class C: public A, public B
{
public:
C()
{
printf("C ");
}
~C()
{
printf("deC ");
}
};
int main()
{
A *a = new C();
delete a;
return 0;
}
A. A B C deA
B. C A B deA
C. A B C deC
D. C A B deC
二、编程题
1、查找输入整数二进制中1的个数 题目链接
2、手套 题目链接
三、选择题题解
1、在公有派生的情况下,派生类中定义的成员函数只能访问原基类的()
A. 公有成员和私有成员
B. 私有成员和保护成员
C. 公有成员和保护成员
D. 私有成员,保护成员和公有成员
正确答案:C
题解:
派生类中访问父类那一部分成员的权限取 继承方式 与 原本基类中成员权限 的较小值,但是如果父类成员是private修饰时,对子类不可见;故选C
2、有如下C++代码:输出答案为
struct A
{
void foo(){printf("foo");}
virtual void bar(){printf("bar");}
A(){bar();}
};
struct B:A
{
void foo(){printf("b_foo");}
void bar(){printf("b_bar");}
};
int main()
{
A *p = new B;
p->foo();
p->bar();
return 0;
}
A. barfoob_bar
B. foobarb_bar
C. barfoob_foo
D. foobarb_fpp
正确答案:A
题解:
本题考察关于虚函数以及多态;首先我们要清楚的是我们的虚表是什么时候生成的;虚表又称虚函数表,在我们编译阶段生成的;而我们的虚表指针是在创建对象的时候生成的,也就是运行状态;而我们的子类在构建对象时,首先是调用父类的默认构造来构造初始化父类那一部分,然后在给我们的虚表指针赋值指向虚表;然后走初始化列表,最后走子类构造函数体;因此本题我们new一个子类时,首先调用父类构造,父类构造函数体中有调用虚函数,但是此时我们子类的虚函数表还没生成,故只能调用父类的虚函数bar,接着创建好的B对象的地址放进p中,下面两个调用就是多态了,foo父类并没有声明成虚函数,故调用父类的foo,接着bar父类定义成了虚函数,且子类对其进行了重写,故调用子类的bar,最后选A;
3、关于抽象类和纯虚函数的描述中,错误的是
A. 纯虚函数的声明以“=0;”结束
B. 有纯虚函数的类叫抽象类,它不能用来定义对象
C. 抽象类的派生类如果不实现纯虚函数,它也是抽象类
D. 纯虚函数不能有函数体
正确答案:D
题解:
D选项描述错误,纯虚函数可以有函数体,只是没有意义;
4、以下程序输出结果是()
class A
{
public:
virtual void func(int val = 1)
{
std::cout<<"A->"<<val <<std::endl;}
virtual void test()
{
func();
}
};
class B : public A
{
public:
void func(int val=0)
{
std::cout<<"B->"<<val <<std::endl;
}
};
int main(int argc ,char* argv[])
{
B*p = new B;
p->test();
return 0;
}
A. A->0
B. B->1
C. A->1
D. B->0
正确答案:B
题解:
本题考察多态的重写相关细节;我们分析题目,func与test都在父类声明成了虚函数;而func在子类中进行了重写,test并没有完成重写;我们用子类的指针调用继承自父类的test函数,test函数有一个隐藏的参数,就是this指针,而这个this指针的类型其实是 A* const this,这种类型;此时我们在test函数里调用func,func前面其实省略了一个this,也就是父类指针调用func,且func为虚函数并在子类中完成了重写,而重写的一个特点是只对实现进行重写,因此我们仅仅只是把函数体替换,缺省值不变,故打印的是B选项;
5、下面程序的输出是()
class A
{
public:
void foo()
{
printf("1");
}
virtual void fun()
{
printf("2");
}
};
class B: public A
{
public:
void foo()
{
printf("3");
}
void fun()
{
printf("4");
}
};
int main(void)
{
A a;
B b;
A *p = &a;
p->foo();
p->fun();
p = &b;
p->foo();
p->fun();
A *ptr = (A *)&b;
ptr->foo();
ptr->fun();
return 0;
}
A. 121434
B. 121414
C. 121232
D. 123434
正确答案:B
题解:
首先我们看p的类型,是A类的指针,我们拿a的地址赋值给p,然后分别调用没有完成重写的foo和完成重写的fun,则分别打印1和2,然后我们将b的地址赋值给p,此时是用子类指针调用,完成多态调教,然后分别调用则打印1和4,最后只是进行了强制类型的转换,也是打印1和4,故选B;
6、如果类B继承类A,A::x()被声明为虚函数,B::x()重载了A::x()方法,在下述语句中哪个x()方法会被调用()
B b;
b.x();
A. A::x()
B. B::x()
C. A::x() B::x()
D. B::x() A::x()
正确答案:B
题解:
多态有两个必不可少的条件,1是虚函数的重写,题目已经提供,2是父类的指针或引用来调用,并没有达成,故没有形成多态,还是调用B类的x函数;故选B;
7、下面关于虚函数的描述,错误的是
A. 在成员函数声明的前面加上virtual修饰,就可把该函数声明为虚函数
B. 基类中说明了虚函数后,派生类中对应的函数也必须说明为虚函数
C. 虚函数可以是另一个类的友元函数,但不能是静态成员函数
D. 基类中说明的纯虚函数在其任何需要实例化的派生类中都必须实现
正确答案:B
题解:
B选项,派生类对应的函数可以添加virtual也可以不添加;没有强制要求;
8、下列为纯虚函数的正确声明的是()
A. void virtual print()=0;
B. virtual void print()=0;
C. virtual void print(){};
D. virtual void print()\;正确答案:B
题解:
语法规定,选B;
9、下面这段代码运行时会出现什么问题?
class A
{
public:
void f()
{
printf("A\n");
}
};
class B: public A
{
public:
virtual void f()
{
printf("B\n");
}
};
int main()
{
A *a = new B;
a->f();
delete a;
return 0;
}
A. 没有问题,输出B
B. 不符合预期的输出A
C. 程序不正确
D. 以上答案都不正确
正确答案:B
题解:
因为我们的父类中并没有将 f 声明成虚函数,因此没有成功完成虚函数的重写,而我们用父类的指针调用时,还是调用的父类的 f 函数,故选B;
10、下面这段代码会打印出什么?
class A
{
public:
A()
{
printf("A ");
}
~A()
{
printf("deA ");
}
};
class B
{
public:
B()
{
printf("B ");
}
~B()
{
printf("deB ");
}
};
class C: public A, public B
{
public:
C()
{
printf("C ");
}
~C()
{
printf("deC ");
}
};
int main()
{
A *a = new C();
delete a;
return 0;
}
A. A B C deA
B. C A B deA
C. A B C deC
D. C A B deC
正确答案:A
题解:
我们在构造子类的时候,会首先构造其父类那一部分,而构造父类的顺序只跟继承的顺序有关,跟初始化列表中分布的顺序无关,因此我们会依次打印 A B C;然后我们调用delete,析构A类型的指针a,故调用A类的析构函数,打印deA;
四、编程题题解
1、查找输入整数二进制中1的个数
思路:我们可以巧妙的利用位运算进行统计,我们通过 num &= num - 1来去掉num二进制中的最后一个1,循环往复,知道全部去完;
#include <iostream>
using namespace std;
int main()
{
int num;
while(cin >> num)
{
// 统计二进制1的个数
int count = 0;
while(num)
{
num &= num - 1;
count++;
}
cout << count << endl;
}
}
2、手套
思路:我们是否可以将左手或者右手的每一种都确保肯定有一只,那么另一边取再拿一只不就可以做到保证整体肯定能凑成一对了么,如下所示;
我们取其中左手或右手中覆盖每一种可能的手套数中的较小的那一个,然后+1(从另一边随意取一只都可以匹配成一对) ,仔细想是不是这么一个道理,但是到这并不能把题完全解出来,我们还没有考虑某一边的某种颜色为0的情况;如下所示;
根据如上,我们可以写出如下代码;
class Gloves {
public:
int findMinimum(int n, vector<int> left, vector<int> right)
{
int left_sum = 0, left_min = INT_MAX;
int right_sum = 0, right_min = INT_MAX;
int sum = 0;
for(int i = 0; i < n; i++)
{
if(left[i] == 0 || right[i] == 0)
sum += left[i] + right[i];
else
{
left_sum += left[i];
left_min = min(left_min, left[i]);
right_sum += right[i];
right_min = min(right_min, right[i]);
}
}
sum += min(left_sum - left_min + 1, right_sum - right_min + 1) + 1;
return sum;
}
};