文章目录
- C/C++笔试练习
- 选择部分
- (1)公有派生
- (2)构造函数内不执行多态
- (3)抽象类和纯虚函数
- (4)多态中的缺省值
- (5)程序分析
- (6)重载和隐藏
- (7)虚函数的描述
- (8)纯虚函数的声明
- (9)虚函数的实现
- (10)程序分析
- 编程题 day15
- 查找输入整数二进制中1的个数
- 手套
C/C++笔试练习
选择部分
(1)公有派生
在公有派生的情况下,派生类中定义的成员函数只能访问原基类的()
A. 公有成员和私有成员
B. 私有成员和保护成员
C. 公有成员和保护成员
D. 私有成员,保护成员和公有成员
答案:C
在公有派生(public derivation)的情况下,派生类中的成员函数可以访问基类的公有成员和保护成员。 私有成员只能由基类自己访问,不能被派生类访问。
(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");}
};
A *p = new B;
p->foo();
p->bar();
那么输出为()
A. barfoob_bar
B. foobarb_bar
C. barfoob_foo
D. foobarb_fpp
答案:A
#include<iostream>
using namespace std;
struct A {
void foo() { printf("foo"); }
virtual void bar() { printf("bar"); }//3.父类的bar虚函数,在子类重写
A() { bar(); }//2.构造子类B对象的时候会先构造父类A
};
//但是这里不会调用子类的bar函数,因为在构造函数期间,虚表尚未形成
//所以也无法实现多态,这里仍然调用的是父类的bar函数
struct B :A {
void foo() { printf("b_foo"); }
void bar() { printf("b_bar"); }
};
int main()
{
A* p = new B;//1.多态的信号 //bar
p->foo(); //barfoo
p->bar();//此时多态实现 //barfoob_bar
}
(3)抽象类和纯虚函数
关于抽象类和纯虚函数的描述中,错误的是
A. 纯虚函数的声明以“=0;”结束
B. 有纯虚函数的类叫抽象类,它不能用来定义对象
C. 抽象类的派生类如果不实现纯虚函数,它也是抽象类
D. 纯虚函数不能有函数体
答案:D
纯虚函数的定义:
virtual void fun()=0;
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
答案: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
int main(void)
{
A a; B b;
A* p = &a;//1.1父类指针指向父类对象
p->foo(); p->fun();//1.2父类指针直接调用父类函数,打印12
p = &b;//2.1由于赋值兼容规则,此时形成多态
p->foo(); p->fun();//2.2父类指针调用父类函数foo(),父类指针调用子类函数fun(),打印14
A* ptr = (A*)&b;//3.1该写法和第二个完全一样,只是把指针p换成了指针ptr
ptr->foo(); ptr->fun();//3.1所以根据多态,打印14
return 0;
}
(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
虽然此时A,B中的x构成多态,但是我们调用的是B类型子类对象,b的函数x,子类对象直接调用子类函数,和多态无关。
(7)虚函数的描述
下面关于虚函数的描述,错误的是
A. 在成员函数声明的前面加上virtual修饰,就可把该函数声明为虚函数
B. 基类中说明了虚函数后,派生类中对应的函数也必须说明为虚函数
C. 虚函数可以是另一个类的友元函数,但不能是静态成员函数
D. 基类中说明的纯虚函数在其任何需要实例化的派生类中都必须实现
答案:B
A. 在C++中,使用virtual关键字可以声明一个虚函数,这使得派生类可以重写该函数。
B. 在C++中,如果基类的成员函数被声明为虚函数,那么派生类可以不用重写这个函数。只有当派生类选择重写这个函数时,它才需要使用virtual关键字。
C. 虚函数可以是另一个类的友元函数,但它们不能是静态成员函数。这是因为静态成员函数是与类关联的,而不是与类的实例关联的。而虚函数是一种动态绑定的机制,它需要在运行时根据对象的实际类型来调用对应的函数。
D.如果一个基类的成员函数被声明为纯虚函数,那么任何派生类都需要实现这个函数。纯虚函数是一种特殊的虚函数,它没有实现,因此需要派生类来实现。
(8)纯虚函数的声明
下列为纯虚函数的正确声明的是()
A. void virtual print()=0;
B. virtual void print()=0;
C. virtual void print(){};
D. virtual void print();
答案:B
纯虚函数的定义:
virtual void fun()=0;
(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(C也对)
class A
{
public:
void f()//父类没有虚函数,没有产生虚表,父类就无法提供指针
{printf("A\n");}
//virtual void x() {};//添加一个虚函数就可以解决
};
class B : public A
{
public:
virtual void f()//释放空间的时候,指针就会非法访问空间
{printf("B\n");}
};
int main()
{
A* a = new B;
a->f();delete a;//非法访问,程序崩溃
return 0;
}
(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
class A{
public:
A()//1.3调用A的构造
{printf("A ");}
~A()//2.1直接调用A的析构,因为没有A~写成虚函数,无法调用子类析构
{printf("deA ");}//会造成内存泄漏
//加上析构即可解决内存泄漏问题
//virtual ~A()
//{printf("deA ");}
};
class B{
public:
B()//1.4调用B的构造
{printf("B ");}
~B()
{printf("deB ");}
};
class C : public A, public B{//1.2此时先调用A的构造,再调用B的构造
public:
C()
{printf("C ");}
~C()
{printf("deC ");}
};
int main()
{
A* a = new C();//1.1创建子类对象C,用父类指针A指向
delete a;//2.1调用A的析构
return 0;
}
编程题 day15
查找输入整数二进制中1的个数
查找输入整数二进制中1的个数
解题思路:本题是计算一个数二进制表示中1的个数,通过(n >> i) & 1可以获取第i位的二进制值,每次n右移一位,可以获取一位的二进制值,右移32次,n变成0,循环终止。
#include<iostream>
using namespace std;
int Count(size_t value)
{
int count = 0;
while(value)
{
value &= (value-1); //表达式只跟1的个数有关系,跟1所在的位置无关
count++;
}
return count;
}
int main()
{
size_t value; //unsigned int
int one_count = 0;
while(cin >> value)
{
one_count = Count(value);
cout<<one_count<<endl;
}
return 0;
}
手套
手套
解题思路:对于非0递增序列a1,a2…an,要想最终取值覆盖每一个种类 n = sum(a1…an) - a1 + 1(也就是总数减去最小值之后加一) 所以对于左右手手套颜色都有数量的序列,想要覆盖每一种颜色,则最小数量leftsum = 左边数量和 - 左边最小值 + 1, rightsum = 右边数量和 - 右边的最小值 + 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++)
{
//对于有0存在的颜色手套,累加
if (left[i]*right[i] == 0)
sum += left[i] + right[i];
//对于左右手都有的颜色手套,执行累加-最小值+1
//找到最小值和总数
else
{
left_sum += left[i];
right_sum += right[i];
left_min = min(left_min, left[i]);
right_min = min(right_min, right[i]);
}
}
//结果为有左右都有数量的手套序列的结果+有0存在的手套数+最后再加一肯定就能保证了
return sum + min(left_sum - left_min + 1, right_sum - right_min + 1) + 1;
}
};