From: http://blog.csdn.net/sailor_8318/article/details/3179044
16、将一个成员函数声明为常量函数有什么作用?
a. 编译器保证该函数不得修改成员变量的值
b. 允许一个常量对象调用此函数
class X
{
public:
void f() const
{
cout<<"haha..."<<endl;
}
};
void main()
{
const X cs;
cs.f();
}
17、volatile关键字有什么作用?
volatile 告诉编译器不要对其做任何自作多情的假设与优化。比如建立一个 const volatile 的对象,其为一个对于程序员只读的易变变量,告诉编译器程序员不得改变此对象,但不是说该对象不会发生改变,来自外界的工具可能会改变它,比如硬件的端口通信。
18、内联函数与普通函数、宏的差别?
使用内联函数的地方,编译器会对其代码进行展开,而不是插入一个跳转。这样提高了函数调用的效率,但同时增大了编译后的目标代码量。内联函数不像宏,它是一个真正的函数,有参数类型检查。内联函数属于编译阶段的工作,而宏属于预处理阶段的工作。注意:在“类中”定义的成员函数都是内联函数。
19、哪两种情况会使编译器放弃内联?
当函数的功能过于复杂时,编译器不会实施内联,这取决于编译器,但通常情况下,循环或者过多的代码不会被内联,因为此时代码执行的时间可能比函数调用的时间多很多,内联失去了意义。
另外一种情况是需要显式或隐式的得到某函数的地址时,编译器要产生地址则必须为其分配内存空间;而进行内联替换时只是将其保存在符号表中,并不为其分配空间。
总之,inline关键词只是对编译器的一种建议,并非强制,是否内联取决于编译器的分析。
20、预处理器的特殊功能:
a. #define DEBUG(X) cout<<#X"="<<X<<endl
b. #define TRACE(X) cout<<#X<<endl, X
c. #define FILE(X) char* X##_string
#为字符串连接符,X经过扩展后将变为“X”,其和"="一起将自动组合为"X="
##为字符连接符,将和相连的字符自动合并构成一个新的字符,即X##_string扩展为X_string
TRACE(X)跟踪函数执行过程,“cout<<#X<<endl, X”为逗号表达式不好出现宏扩展后的异常问题,两句肯定一起执行,若“cout<<#X<<endl;X”则可能出现问题
DEBUG(X)跟踪打印变量的值
#define DEBUG(X) cout<<#X"="<<X<<endl
#define TRACE(X) cout<<#X<<endl, X
#define FILE(X) char* X##_string
int f(){
return 9;
}
void main()
{
char i[]="haha";
DEBUG(i);
for(int j=0;j<5;j++)
TRACE(f());
FILE(one)=i;
cout<<one_string<<endl;
}
/*
i=haha
f()
f()
f()
f()
f()
haha
*/
21、有没有代码能在主函数的第一行代码之前或最后一行代码之后执行?
全局对象的构造函数将在main函数之前运行。析构在main函数之后运行。
函数内部的static对象的构造函数将在第一次调用该函数时调用,main函数结束之后执行。但其析构会在全局对象之前,因为所有对象的析构顺序和构造顺序相反,即全局对象在函数内部的static对象前构造,在后面析构。若包含静态局部对象的函数未被调用,则也不进行析构。
可以通过atexit函数指定当离开main或者调用exit时所要执行的动作。其在所有的析构函数之前运行。
class Obj
{
char cT;
public:
Obj(char c)
{
cT=c;
cout<<"Obj::Obj() for "<<c<<endl;
}
~Obj()
{
cout<<"Obj::~Obj() for "<<cT<<endl;
}
};
Obj A('A'); //全局对象在main之前构造
void f()
{
static Obj B('B');
}
void main()
{
cout<<"inside main()"<<endl;
f();
cout<<"leaving main()"<<endl;
}
void main(){
cout<<"inside main()"<<endl;
f();
cout<<"leaving main()"<<endl;
}
OUTPUT:
Obj::Obj() for A
inside main()
Obj::Obj() for B
leaving main()
Obj::~Obj() for B //在A前析构
Obj::~Obj() for A
22、static 关键字的作用:
无论是C还是C++,static都具备两个基本意义,如下:
在固定的位置只分配一次内存,对象创建在静态数据区中而非堆栈中,这就是静态内存的概念。
对特定单元可见,static控制着名字的可见性,其同时描述了链接的概念,指明了链接器可以见到的名字。
Staic无论表示内存的物理位置还是文件中的可见性,其基本意义为保持其原有位置。
以下都是全局定义的变量
extern int a=0; ===> int a=0; (静态)
extern void f(); ===> void f();
static int a=0; ===> 本文件内可见
static void f(); ===> 本文件内可见
23、名字空间的使用:
namespace simon{
class A{
public:
void print(){
cout<<"this is simon::A"<<endl;
}
};
char str[]="this is simon::str";
}
void main(){
simon::A v;
v.print();
using namespace simon;
cout<<str<<endl;
}
24、静态成员函数与普通成员函数有什么区别?
静态成员函数只能访问静态成员变量与静态成员函数。为什么呢?想一想那个this指针,静态成员函数是没有this指针的。
25、在C++中用到一个C库中的函数,为了防止编译器按照C++的方式对符号进行访问以致无法定位函数实体该如何做?
extern"C" float f(int a, float b);
c++中 f() ===> _f_int_float
c中 f() ===> _f
C++中为了支持函数重载和类型安全检查,会对编译后的函数名字进行装饰,如生成_f_int_char之类的。因此在C++中无法利用C库函数,需要使用链接交换指导符extern,告诉C++不要进行装饰。
26、如何改变一个指针常量的指向?
void main()
{
int i(1);
int j(2);
int * const p=&i;
int * pp=(int*)&p;
*pp=(int)&j;
cout<<*p<<endl;
}
强制转换,通过p的地主改变其值,从而改变其指向
27、解释下面例子错误的原因
const int iii=20;
int & q=iii; //错误,非常量引用不能引用常量
int & qq=20; //错误,非常量引用不能引用常量
const int & qqq=iii; //正确
qqq=23; //错误,常量不能作为左值
引用必须跟一块合法的存储空间联系起来,其和指针区别如下:
a.引用必须被初始化。而指针可以不
b. 引用一旦指向一个对象,就不能再指向其它。非const指针可以随意指向任意该类对象
c. 不能引用NULL ,不能引用常量(除非是常量引用)
28、当用非const引用作函数参数时,其参数必须是非常量,即不能是直接值或返回的临时变量
void f(int &){}
void g(const int &){}
void main(){
//f(1);
g(1);
}
29、什么情况下需要一个拷贝构造函数?
需要用类作值传递时value pass
class X;
void f(X x2);
X x1;
f(x1);
X x2=x1;
30、拷贝构造函数的形式: X::X(X&){}
31、尽量避免类的值传递,用什么方法可以阻止用户的类值传递?
只要声明一个私有的拷贝构造函数即可:
class X{
X(X& x) {
cout<<"hehe"<<endl;
}
public:
X(){}
};
void main(){
X xx;
//! X x2=xx;
}