由联发科(联发博动)MTK 2010校园招聘的一道笔试题想到的。
这道笔试题内容是
struct S
{
int value;
void foo()
{
printf("in foo()\n");
}
void foo() const
{
printf("in foo() const\n");
}
virtual void Vfoo()
{
printf("in virtual foo()\n");
}
};
1) sizeof(S)和sizeof(int)哪个大?为什么?
答:很显然,为实现虚函数,存在一个vptr指向虚表,sizeof(S)较大,为8。
2)
struct S *p;
int main()
{
p->foo();
p->Vfoo();
return 0;
}
输出什么?
答:
如果p没有实例化,运行时会报错。如果中间实例化了,则
in foo()
in virtual foo()
3)
可以输出为
in foo()
in foo() const
的成员函数吗?如何可以请实现如下
void f() const
{
__________
__________
}
。如果不可以,为什么?
答:可以实现。有两种方法:
方法一:
void f() const
{
foo();
S s; s.foo();
}
但是我想这道题肯定不是想这么考你,在成员函数里实例化一个自己难道不是一件很奇怪的事情吗?当然了,这样也能得到问题的解答。
下面这个解法应该是出题的人想看到的:
方法二:
void f() const
{
foo();
(const_cast<S*>(this))->foo();
}
这里采用了const_cast关键词。首先说一下const_cast的作用,它可以在常数值(指针)类型和非常数值(指针)类型之间执行转换,也就是说,可以将常数类型转换为非常数类型,也可以将非常数类型转换为常数类型。
我们知道,成员函数后面跟const(以下简称const成员函数),编译器会控制该函数的行为,使其在一般状态下不能改变其成员变量,所以也自然就不能调用非const的成员函数。
其实,在编译器底层实现的时候,只是将隐藏的this关键字附加了const修饰,这样就通过一个很简单的方式,可以使编译器得以控制const成员函数函数的行为,而不是很多人想象的,还要一个函数一个函数递归检查。
所以,我们只需要在这里把const的this指针转换为非const的指针,编译器就会去调用S的非const的foo()这个函数。
这里我们也可以推广到另外一个问题,如果判断void foo() const这样一个成员函数能不能改变其成员变量呢?
这也许是一个判断题,也许会是在一个选择当中,当然也可能需要你简述其原理。通过上述的分析,我们已经看到了,这其实在C++标准中是可以的,只需要进行const_cast转换就可以了,只不过形如*_cast这样的,大多都只是C++标准面向底层的灵活性可操作性的体现,但很多时候都是一样非正常的行为。
如果不相信的话,你可以把struct S中的非const的foo()修改如下:
void foo()
{
value = 6;
printf("in foo() %d\n", value);
}
将输出in foo() 6
最后总结一句话:任何时候,只要抓住一个简单的概念,就是用const对变量进行修饰的时候,无论是对象还是对象的指针,编译器仅仅是默认在正常情况下(特别声明)不允许修改其中的内容。