经典C++笔试题解析2


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; 

}


  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值