题目(一)求输出结果
#include <iostream>
using namespace std;
struct Point3D
{
int x;
int y;
int z;
};
int main ()
{
Point3D *pPoint = NULL;
int offset = (int) (&(pPoint)->z);
printf ("%d", offset);
return 0;
}
答案:输出8。由于在pPoint->z的前面加上了取地址符号,运行到此时的时候,会在pPoint的指针地址上加z在类型Point3D中的偏移量8。由于pPoint的地址是0,因此最终offset的值是8。&(pPoint->z)的语意是求pPoint中变量z的地址(pPoint的地址0加z的偏移量8),并不需要访问pPoint指向的内存。只要不访问非法的内存,程序就不会出错。这也是求在一个结构体(类中)某个变量偏移位置的方法。
题目(二)
#include <iostream>
using namespace std;
class A
{
private:
int n1;
int n2;
public:
A ():n2 (0), n1 (n2 + 2)
{
}
void Print ()
{
std::cout << "n1: " << n1 << ", n2: " << n2 << std::endl;
}
};
int main ()
{
A a;
a.Print ();
return 0;
}
答案:输出n1是一个随机的数字,n2为0。在C++中,成员变量的初始化顺序与变量在类型中的申明顺序相同,而与它们在构造函数的初始化列表中的顺序无关。因此在这道题中,会首先初始化n1,而初始n1的参数n2还没有初始化,是一个随机值,因此n1就是一个随机值。初始化n2时,根据参数0对其初始化,故n2=0。
题目(三)
#include <iostream>
using namespace std;
class A
{
private:
int value;
public:
A (int n)
{
value = n;
}
A (A other)
{
value = other.value;
}
void Print ()
{
std::cout << value << std::endl;
}
};
int main ()
{
A a = 10;
A b = a;
b.Print ();
return 0;
}
答案:编译错误。在复制构造函数中传入的参数是A的一个实例。由于是传值,把形参拷贝到实参会调用复制构造函数。因此如果允许复制构造函数传值,那么会形成永无休止的递归并造成栈溢出。因此C++的标准不允许复制构造函数传值参数,而必须是传引用或者常量引用。在Visual Studio和GCC中,都将编译出错。gcc中编译为“错误:无效的构造函数:您要的可能是 ‘A (const A&)’”。
题目(四)
#include <iostream>
using namespace std;
class A
{
public:
virtual void Fun (int number = 10)
{
std::cout << "A::Fun with number " << number;
}
};
class B:public A
{
public:
virtual void Fun (int number = 20)
{
std::cout << "B::Fun with number " << number;
}
};
int main ()
{
B b;
A & a = b;
a.Fun ();
}
答案:输出B::Fun with number 10。由于a是一个指向B实例的引用,因此在运行的时候会调用B::Fun。但缺省参数是在编译期决定的。在编译的时候,编译器只知道a是一个类型a的引用,具体指向什么类型在编译期是不能确定的,因此会按照A::Fun的声明把缺省参数number设为10。这一题的关键在于理解确定缺省参数的值是在编译的时候,但确定引用、指针的虚函数调用哪个类型的函数是在运行的时候。
题目(五)
#include <iostream>
using namespace std;
bool
Fun1 (char *str)
{
printf ("%s\n", str);
return false;
}
bool
Fun2 (char *str)
{
printf ("%s\n", str);
return true;
}
int main ()
{
bool res1, res2;
res1 = (Fun1 ("a") && Fun2 ("b")) || (Fun1 ("c") || Fun2 ("d"));
res2 = (Fun1 ("a") && Fun2 ("b")) && (Fun1 ("c") || Fun2 ("d"));
return res1 || res2;
}
答案:打印出4行,分别是a、c、d、a。
在C/C++中,与、或运算是从左到右的顺序执行的。在计算rest1时,先计算Fun1(“a”) && Func2(“b”)。首先Func1(“a”)打印出内容为a的一行。由于Fun1(“a”)返回的是false, 无论Func2(“b”)的返回值是true还是false,Fun1(“a”) && Func2(“b”)的结果都是false。由于Func2(“b”)的结果无关重要,因此Func2(“b”)会略去而不做计算。接下来计算Fun1(“c”) || Func2(“d”),分别打印出内容c和d的两行。在计算rest2时,首先Func1(“a”)打印出内容为a的一行。由于Func1(“a”)返回false,和前面一样的道理,Func2(“b”)会略去不做计算。由于Fun1(“a”) && Func2(“b”)的结果是false,不管Fun1(“c”) && Func2(“d”)的结果是什么,整个表达式得到的结果都是false,因此Fun1(“c”) && Func2(“d”)都将被忽略。
题目(六)
#include <iostream>
using namespace std;
class Base
{
public:
void print ()
{
doPrint ();
}
private:
virtual void doPrint ()
{
cout << "Base::doPrint" << endl;
}
};
class Derived:public Base
{
private:
virtual void doPrint ()
{
cout << "Derived::doPrint" << endl;
}
};
int main ()
{
Base b;
b.print ();
Derived d;
d.print ();
return 0;
}
答案:输出两行,分别是Base::doPrint和Derived::doPrint。在print中调用doPrint时,doPrint()的写法和this->doPrint()是等价的,因此将根据实际的类型调用对应的doPrint。所以结果是分别调用的是Base::doPrint和Derived::doPrint2。如果感兴趣,可以查看一下汇编代码,就能看出来调用doPrint是从虚函数表中得到函数地址的。