专注于服务器编程、网络编程

~~保持一颗平常心~~持之以恒~~
posts - 18, comments - 7, trackbacks - 0, articles - 0
  C++博客 :: 首页 :: 新随笔 :: 联系 :: 聚合  :: 管理

C++ 面试题

Posted on 2010-04-25 15:00 ~William~ 阅读(1555) 评论(0)  编辑 收藏 引用 所属分类: c++基础

C++ 面试题

1.类成员指针

Class test

{

Public:

         Int fun(int) const;

         Int fun(int);

         Static int fun(int);

         Int iTemp;

}

1.1   非静态成员函数指针
定义:
int (Test::*pFun)(int) = &Test::fun;
int (Test::*pFunConst)(int)const = &Test::fun;
使用:
Test a;
const Test b;
(a.*pFun)(2)
(a.*pFunConst)(2);
(b.*pFunConst)(2);
不能用(b.*pFun)(2);

1.2   非静态成员变量
int Test::*pInt = &Test::iTemp;
(a.*pInt) = 3;

1.3   静态成员函数指针
int (*pFun)() = &Test::fun;
int (*pFun)() = Test::fun; 都正确;(注:定义无域操作符)
使用:
(*pFun)()
pFun() 都正确;

2.非成员函数指针和静态成员函数一致。
3.非成员函数和静态成员函数上不允许修饰符。例如 void fun() const; void fun() volatile;
但非静态 成员函数允许constvolatile等修饰符。
4.变量修饰符

 
auto:指定数据存储在栈中。局部变量默认为auto。该修饰符不能用于成员变量和全局变量。
static
局部变量表示存储在静态空间,全局变量表示不允许外部引用。
volatile
:表示该变量可能随时改变,不要做任何假设优化。
mutale
去除成员变量的const属性。
extern
:全局变量默认为extern属性,表示可被外部引用,此时与static相对。
extern int a =2;
表示定义一个可被外部引用的变量。
extern int a;
表示引用外部变量。

 

5.数据类型隐式转换

短数据->长数据 (eg: float -> double)
有符号->无符号 (eg: int -> unsigned int )PS: 所以 int(-1)>unsigned int(1);
低精度->高精度 (eg: int -> float)

6.memcpy 防重叠覆盖机制,strcpy 没有。
7.float表示

共计32位,折合4字节
由最高到最低位分别是第313029……0
31
位是 符号位,1表示该数为负,0反之。
30-23
位,一共8位是指数位。
22-0
位,一共23位是尾数位。
8位分为一组,分成4组,分别是A组、B组、C组、D组。
每一组是一个字节,在内存中逆序存储,即:DCBA

8.不能在类的声明中初始化类常量,而只能在构造函数初始化列表来初始化
9.类中的枚举常量不占用对象的存储空间
10.有时候函数原本不需要返回值,但为了增加灵活性如支持链式表达,可以附加返回值。
11.赋值函数,应当用引用传递的方式返回String 对象。如果用值传递的方式,虽然功能仍然正确,但由于return 语句要把 *this 拷贝到保存返回值的外部存储单元之中,增加了不必要的开销,降低了赋值函数的效率。
12.对于非内部数据类型的对象而言,光用maloc/free 无法满足动态对象的要求。对象在创建的同时要自动执行构造函数, 对象在消亡之前要自动执行析构函数。如果用free 释放“new 创建的动态对象,那么该对象因无法执行析构函数而可能导致程序出错。如果用delete 释放“malloc 申请的动态内存,理论上讲程序不会出错,但是该程序的可读性很差。
13.如果用new 创建对象数组,那么只能使用对象的无参数构造函数,delete时如果对象没有析构函数,则deletedelete[]是功能相同的。
14.只能靠参数而不能靠返回值类型的不同来区分重载函数。编译器根据参数为每个重载函数产生不同的内部标识符。并不是两个函数的名字相同就能构成重载。全局函 数和类的成员函数同名不算重载,因为函数的作用域不同。
15.关键字inline

必须与函数定义体放在一起才能使函数成为内联,仅将inline 放在函数声明前面不起任何作用。定义在类声明之中的成员函数将自动地成为内联函数。
以下情况不宜使用内联:
1)如果函数体内的代码比较长,使用内联将导致内存消耗代价较高。
2)如果函数体 内出现循环,那么执行函数体内代码的时间要比函数调用的开销大。

16.只有静态常量整型数据成员才可以在类中初始化,普通成员只能在初始化列表或函数内初始化,常量成员只能在初始化列表。成员对象初始化的次序完全不受它们在 初始化表中次序的影响,只由成员对象在类中声明的次序决定。
17.拷贝构造函数和赋值函数非常容易混淆,常导致错写、错用。拷贝构造函数是在对象被创建时调用的,而赋值函数只能被已经存在了的对象调用。
18.不想编写拷贝构造函数和赋值函数,又不允许别人使用编译器生成的,则只需将拷贝构造函数和赋值函数声明为私有函数,不用编写代码。
19.“const T”“T const”总是都被允许的,而且是等效的。
注意在常量指针(const pointer)中,“const”永远出现在“*”之后。
例如:
int *const p1 = q; //
指向int 变量的常量指针
int const* p2 = q; //
指向int 常量的指针
const int* p3 = q; //
指向int 常量的指针
20.一个常见的微妙问题是,一个函数风格的宏并不遵守函数参数传递的规则。
21.没有引用数组,但可有指向数组的引用,并且保留数组的边界。
22.左值拥有保存值的位置,而右值则没有相关地址,只是简单值。
23.负索引是可以的,如p[-2](-2)[p]都是可以的(p必然不能是数组名),但必须保持不越界。
 sum=p()+q()+r();不能保证p(),q(),r()调用的顺序。
逗号运算符","可以保证求值顺序.result= ( p(),q(),r() );是先求p(),q(),然后将r()赋给result
24.在if的条件里声明变量,且可在真假分支里面使用。
const int * const * p;p是个指针,指向常指针的,常指针指向一个常量int
25.不能用空白初始化列表来规定默认的对象初始化.

class a;
a A(); //
会警告,看起来像函数声明
a *p=new a(); //ok
a *p=new a;   //ok

26.可以写一句只有数字的代码,如1234;(void)0;可以编译执行,相当于nop
27.给函数指针赋值时可以对函数名取地址也可以不取,通过函数指针调用函数时可以用*也可不用。
28.static_cast可以转换基本数据类型(int->char)void*和有类型指针、基类和派生类指针的转换(多重继承也行,它可重新计算偏移地址),但是不能转换如(int*->char*)
29.dynamic_cast主要用于执行"安全的向下转型",reinterpret_cast可执行任何转换,const_cast执行去 const转换。
30.将取地址运算符用到完全限定的类成员名(包括变量和函数),就能获得指向成员的地址。使用形式为"X::*"来声明一个指向类X成员的指针。注意声明成员 函数指针的时候不能像普通函数指针可以省略&*的使用,但静态成员函数则除外,它和普通函数一致。成员指针和普通指针不一样,并非指向一个内存 区域,而是相当于一个结构的偏移量,当它和具体的对象结合就能指向特定对象的特定成员。
31.当把派生类对象赋给基类对象的时候会产生切割现象,即针对派生类的数据和行为将产生切割。
32.多维数组的第1个元素是数组而非普通类型。
33.在含有单参数构造函数的类中注意隐式转换。如String s="Hello";
34.函数对象是重载函数调用运算符的类对象。
35.引用需要用左值进行初始化,但指向常量的引用除外,编译器将创建一个临时左值。如const int c=12;//ok 一般情况下编译器产生的临时对象的生命期在它所在的最大表达式范围内,但用临时对象初始化常量对象的引用时会让编译器保证临时对象和引用生命周期一样。
36.可以将基类的成员指针(变量或函数)安全的转换为指向派生类成员的指针,但反之则不安全。
37.函数参数的传递是采用拷贝构造函数而非赋值操作。对未初始化的对象赋值可能会出现意外,如类中含有未初始化指针。
38.声明但不定义私有的拷贝构造和赋值运算将会关闭类的复制操作。并且赋值运算、拷贝构造函数和析构函数不会被继承,对派生类重载赋值运算时需要调用基类的赋 值运算。
39.在构造函数里对成员变量初始化,比较好的方式是使用初始化列表。在初始化列表中静态成员和数组不能被初始化。
类的初始化顺序是虚拟基类的成员->非虚基类成员->类自身成员,和初始化列表的顺序无关。
含有虚拟基类和不含的类在成员布局上不一样,含有虚拟基类的类将虚拟基类的数据放在最后面。另外如B:virtual A,C:virtual A,D:B,C;(均是虚继承)D的构造函数将对A初始化一次(即使在初始化列表没有显式初始化A)B,C将不再对A初始化。
所有静态数据(全局变量和静态存储变量)在使用前如未初始化其值都为0.全局变量可以存储在静态初始化区和未初始化区。
40.RVO返回值优化,是指在函数返回中执行拷贝初始化到直接初始化(使用带非对象参数的构造函数)的转换,NRVRVO类似,但使用命名局部变量来保存返 回值。p160
41.重载、覆盖和隐藏的区别

重载的特征:在同一个类,函数名相同,参数不同,virtual可有可无。
覆盖的特征:在两个类(基类和派生类),函数名和参数都相同, 且必须有virtual关键字。
隐藏的特征:基类函数名和派生类函数名相同参数不同,且不管是否有关键字。或函数名、参数均相同,但基类 函数没有virtual(有的话就是覆盖)
不能覆盖而只能隐藏基类非虚函数。

42.相同类型的所有对象公用一个虚函数表,在单继承下不管有多少个虚函数都只有一个虚函数表指针。覆盖就是在为派生类构造虚函数表时用派生类的函数地址替换基 类成员函数地址的过程。
43.使用常量类成员可能在对类对象赋值的时候产生问题。
44.有时候我们可能会看到 if (NULL == p) 这样古怪的格式。不是程序写错了,是程序员为了防止将 if (p == NULL) 误写成 if (p = NULL),而有意把p NULL 颠倒。

 

 


只有注册用户登录后才能发表评论。
网站导航: 博客园   IT新闻   BlogJava   博问   Chat2DB   管理