面试题1:指出下段程序的错误,并解释它为什么是错误的。
#include<iostream.h>
class Base
{
public:
int val;
Base()
{
val = 1;
};
};
class Derive: Base
{
public:
int val;
Derive(int i)
{
val = Base::val + i;
};
};
int main(int, char**,char**)
{
Derive d(10);
cout<<d.Base::val<<endl<<d.val<<endl;
return 0;
}
答案:class Derive:Base错误,因为默认的继承关系为私有继承,私有继承时子类的对象不
能访问父类的成员,导致cout<<d.Base::val<<endl<<d.val<<endl;出错,应将class Derive:Base
改为class Derive: public Base。
改正后运行结果:
1
11
面试题2:用C++设计一个不能被继承的类
答案:
template <typename T> class A
{
friend T;
private:
A() {}
~A() {}
};
class B : virtual public A<B>
{
public:
B() {}
~B() {}
};
class C : virtual public B
{
public:
C() {}
~C() {}
};
void main(void)
{
B b;
//C c;
return ;
}
编译结果:
error C2248: 'A<class B>::A<class B>' : cannot access private member declared in class 'A<class B>'
面试题3:下面说法正确的是那个?
class A
{
virtual void func1() {};
void func2();
};
class B: public virtual A
{
void func1()
{
cout<<"func1 in class B"<<endl;
}
virtual void func2()
{
cout<<"func2 in class B"<<endl;
}
};
根据这段代码,判断以下说法正确的是:
A:A中的func1和B中的func2都是虚函数。
B:A中的func1和B中的func2都不是虚函数。
C:A中的func2是虚函数和B中的func1不是虚函数。
D:A中的func2和B中的func1都是虚函数。
答案:答案A是正确的。
面试题4:写出程序的打印结果
#include <iostream.h>
class A
{
public:
virtual void print(void)
{
cout<<"A::print()"<<endl;
}
};
class B:public A
{
public:
virtual void print(void)
{
cout<<"B::print()"<<endl;
};
};
class C:public B
{
public:
virtual void print(void)
{
cout<<"C::print()"<<endl;
}
};
void print(A a)
{
a.print();
}
void main(void)
{
A a, *pa, *pb, *pc;
B b;
C c;
pa = &a;
pb = &b;
pc = &c;
a.print();
b.print();
c.print();
pa->print();
pb->print();
pc->print();
print(a);
print(b);
print(c);
}
答案:
A::print()
B::print()
C::print()
A::print()
B::print()
C::print()
A::print()
A::print()
A::print()
面试题5:访问基类的私有虚函数
写出以下程序的输出结果
#include <iostream.h>
class A
{
virtual void g()
{
cout<<"A::g"<<endl;
}
private:
virtual void f()
{
cout<<"A::f"<<endl;
}
};
class B:public A
{
void g()
{
cout<<"B::g"<<endl;
}
virtual void h()
{
cout<<"B::h"<<endl;
}
};
typedef void (*Fun)(void);
void main()
{
B b;
Fun pFun;
for(int i = 0; i < 3; i++)
{
pFun = (Fun)*((int*)*(int*)(&b)+i);
pFun();
}
}
答案:
B::g
A::f
B::h
面试题6:简述成员函数的重写、重载和隐藏的区别
答案:
(1)重写和重载主要有以下几点不同。
*范围的区别:被重写函数和重写函数在两个类中,而重载和被重载函数在一个类中。
*参数的区别:被重写函数和重写函数的参数列表一定相同,而被重载函数和重载函数的参数列表一定不同。
*virtual的区别:重写的基类中被重写的函数必须要有virtual修饰,而重载函数和被重载函数可以被
virtual修饰,也可以没有。
(2)隐藏和重写、重载有以下几点不同。
*与重载的范围不同:和重写一样,隐藏函数和被隐藏函数不再同一个类中。
*参数的区别:隐藏函数和被隐藏的函数的参数列表可以相同,也可以不同,但是函数名肯定要相同。当参数不
相同时,无论基类中的参数是否被virtual修饰,基类的函数都是被隐藏,而不是被重写。
面试题7:简述多态实现的原理
答案:编译器发现一个类中有虚函数,便立即会为此类生成虚函数表vtable。虚函数表的各表项为指向对应虚
函数的指针。编译器还会在此类中隐含插入一个指针vptr(对VC编译器来说,它插在类的第一个位置上)指向
虚函数表。调用此类的构造函数时,在类的构造函数中,编译器会隐含执行vptr和vtable的关联代码,将vptr
指向对应的vtable,将类与此类的vtable联系了起来。另外在调用类的构造函数时,指向基础类的指针此时已
经变成指向具体类的this指针,这样依靠此this指针即可得到正确的vtable。如此才能正确与函数体进行连接,
这就是动态联编,实现多态的基本原理。