目录
第一题(虚表指针的位置)
代码执行后,a和b的值分别为?
#include <iostream>
using namespace std;
class Test{
public:
int a;
int b;
virtual void fun() {}
Test(int temp1 = 0, int temp2 = 0)
{
a=temp1 ;
b=temp2 ;
}
int getA()
{
return a;
}
int getB()
{
return b;
}
};
int main()
{
Test obj(5, 10);
// Changing a and b
int* pInt = (int*)&obj;
*(pInt+0) = 100;
*(pInt+1) = 200;
cout << "a = " << obj.getA() << endl;
cout << "b = " << obj.getB() << endl;
return 0;
}
A 200 10
B 5 10
C 100 200
D 100 10
首先我们创建了一个Test类型的对象,然后将其地址强制转换成int*赋值给了pInt,也就是得到了起始位置的4个字节的地址(32)位
如果没有虚函数的话,也就是将下面这行代码注释掉
我们的a和b刚好是在我们的对象前面的两个成员,
所以*(pInt+0)其实就是我们的a的值,我们将其修改为100
*(pInt+1)其实就是我们的b的值,我们将其修改为200
但是有了这里的虚函数的话
我们的对象的首位置是我们的虚表指针
然后+1之后的修改,实际上修改的是我们的a成员
也就是我们这里将我们的虚表赋值为了100,然后将我们的a成员赋值为了200
然后我们的b成员还是原来的10
由于这里没有访问虚函数,所以没有报错,但实际上如果通过多态访问虚函数表,就会报错,因为我们的虚表指针已经不能找到我们正确的虚表了
A
第二题(私有继承的权限问题)
下列程序的输出结果:
#include <iostream>
using namespace std;
class A
{
public:
void print()
{
cout << "A:print()";
}
};
class B: private A
{
public:
void print()
{
cout << "B:print()";
}
};
class C: public B
{
public:
void print()
{
A:: print();
}
};
int main()
{
C b;
b.print();
}
A A:print()
B B:print()
C 编译出错
B继承A,但是一个私有继承
C共有继承B
我们这里创建了一个C的对象,想要去调用A的方法
程序会出错,因为B私有继承A,那么A中的所用成员在B中表现为私有成员
那我们的C类是B类的子类,子类没有办法访问父类的私有成员。
C
第三题(运行时多态和编译时多态)
下面关于多态性的描述,错误的是()
A C++语言的多态性分为编译时的多态性和运行时的多态性
B 编译时的多态性可通过函数重载实现
C 运行时的多态性可通过模板和虚函数实现
D 实现运行时多态性的机制称为动态绑定
C中的模板和多态没有关系,模板是为了实现泛型编程,这两个不是同一个机制
C
第四题(多态的条件)
写出下面程序的输出结果
#include <iostream>
class A
{
public:
void FuncA()
{
printf( "FuncA called\n" );
}
virtual void FuncB()
{
printf( "FuncB called\n" );
}
};
class B : public A
{
public:
void FuncA()
{
A::FuncA();
printf( "FuncAB called\n" );
}
virtual void FuncB()
{
printf( "FuncBB called\n" );
}
};
void main( void )
{
B b;
A *pa;
pa = &b;
A *pa2 = new A;
pa->FuncA(); //( 3)
pa->FuncB(); //( 4)
pa2->FuncA();//( 5)
pa2->FuncB();
delete pa2;
}
A FuncA called FuncB called FuncA called FuncB called
B FuncA called FuncBB called FuncA called FuncB called
C FuncA called FuncBB called FuncAB called FuncBB called
D FuncAB called FuncBB called FuncA called FuncB called
创建一个子类对象b
父类指针指向子类对象pa
父类指针指向父类对象pa2
pa->FuncA()由于我们的pa是父类指针指向子类对象,但是父类的FuncA()中并没有写virtual,所以不满足多态的条件,直接调用父类的FuncA()方法,打印FuncA called
pa->FuncB()由于这里是父类的指针指向子类的对象并且父类中的FuncB前面有virtual,满足多态的条件,所以我们这里直接调用子类的FuncB,打印FuncBB called
pa2->FuncA 这里的pa2是父类的指针指向父类的对象,所以它是直接调用父类的FuncA方法,打印FuncA called
pa2->FuncB 这里的pa2是父类的指针指向父类的对象,不满足多态的条件,所以它是直接调用父类的FuncB方法,打印FuncB called
B
第五题(多态+32位下指针大小)
#include<iostream>
using namespace std;
class Base
{
public:
virtual int foo(int x)
{
return x * 10;
}
int foo(char x[14])
{
return sizeof(x) + 10;
}
};
class Derived: public Base
{
int foo(int x)
{
return x * 20;
}
virtual int foo(char x[10])
{
return sizeof(x) + 20;
}
} ;
int main()
{
Derived stDerived;
Base *pstBase = &stDerived;
char x[10];
printf("%d\n", pstBase->foo(100) + pstBase->foo(x));
return 0;
}
在32位环境下,以上程序的输出结果是?
A 2000
B 2004
C 2014
D 2024
我们首先创建了一个子类对象,然后用父类的指针指向子类的对象
父类的指针访问foo(100),这里满足了多态调用的条件,调用的是子类的方法,也就是我们下面两个中,更下面的这个方法
100*20=2000
这里只要传入一个指针数组就可以调用这个方法,跟你是不是14没有关系
这里我们是父类的指针,并且不满足多态的条件,所以我们直接调用的就是父类的foo方法。因为我们在32位的系统下,我们的指针的大小为4个字节,所以这里返回的是
4+10=14
最后我们将这两个值加起来也就是2000+14=2014
C