关于面试,那些我彻底不知道的知识

这里记录一下在找工做前的复习过程当中那些让我怀疑我是否是真的学过计算机的知识点。。html


C/C++

cout的格式化输出

cout << boolalpha << (1 == 2);

输出false
参考连接:http://www.cnblogs.com/devymex/archive/2010/09/06/1818754.html数组

const与指针

const*的左侧,如 const int *aint const *a,不能改变指针a指向的内容的值
const*的右侧,如 int* const a,指针a自己为常量,不能改变a的指向ide

我的以为把const放在类型符号后边意义更明确一些。。函数

mutable与const

在类中,修饰为mutable的成员变量能够被修饰为const的成员函数修改优化

class A {
 public:
  mutable int a;
  void set_a(int n) const {
    a = n;
  }
};

sizeof括号内的秘密

sizeof()结果由编译时肯定,()内代码不被执行ui

int a = 0;
sizeof(a = 1);

a的值不会被改变this

指针和引用的区别与联系

注意,引用也是要占用内存空间的,内容是被引用的变量的地址,同指针同样spa

struct st1
{
	int a;
	int &b;
	st1(int n) : a(n), b(a) {}
};

struct st2
{
	int a;
	int *b;
	st2(int n) : a(n), b(&a) {}
};

st1 s1(10);
st2 *ps2 = reinterpret_cast<st2*>(&s1);
cout << *(ps2->b); // 10

参考连接:http://blog.csdn.net/thisispan/article/details/7456169.net

指针数组,仍是数组指针,仍是函数指针数组,仍是。。

int *a[10];//包含十个元素的数组,数组元素是整型指针
int *(a[10]);//同上
int (*a)[10];//指向具备十个整型元素的数组的指针
int (*a)();//指向无参数且返回整型的函数的指针
int (*a[10])();//包含十个元素的数组,数组元素是指向无参数且返回整型的函数的指针
int (**a)[10];//指向一维数组指针的指针,数组具备十个整型元素
int *(*a)[10];//指向一维数组的指针,数组具备十个整型指针元素
int (*(*a)(int))();//指向具备一个整型参数且返回函数指针的函数的指针,返回的函数指针指向无参数且返回整型的函数

数组名取址?

int a[5] = {1, 2, 3, 4, 5};
int *p = (int*)(&a + 1);
cout << (int)*(p - 1);

输出为5
数组名a是指向数组第一个元素的指针,&a是指向数组的指针,虽然两个指向同一个地址,可是&a + 1其实是将指针向后移动了sizeof(a),也就是20个字节,与a + 1移动一个字节不一样
在这里p相似于二维数组线程

this指针从哪来

this指针其实是类成员函数的第一个参数,由编译器自动添加,经过寄存器传递,整个生命周期同函数参数一致

容器与迭代器

删除vector等连续空间的容器元素后,相应迭代器会失效

struct与class

structclass除了默认访问控制不一样之外,其余彻底相同。
struct默认访问控制是publicclass默认访问控制是private

构造函数初始化列表

除开父类构造函数,成员变量初始化按照成员变量在类中申明的顺序执行,与初始化列表顺序无关

类与内联函数

除了虚函数和静态成员函数,其余函数能够是内联的,包括构造函数和析构函数。
事实上,若是成员函数在类申明中定义,那么默认是内联的。类申明外定义的函数能够用inline修饰为内联的。但须要注意的是,内联函数是内部连接的,只能在本文件内被调用。

//A.h
class A {
 public:
  A() { cout << "A()" << endl; }
  inline virtual ~A() { cout << "~A()" << endl; }
  inline void func1() { cout << "func1" << endl; }
  void func2();
};

//A.cc
inline void A::func2() { cout << "func2" << endl; }

//main.cc
A *a = new A;
a->func1();
a->func2();// 编译失败
delete a;

看起来好像复制构造函数

class A {
 public:
  int m;
  A(int n) : m(n) {}
  A(float n) : m(n * 2) {}
};

A a = 10;  // a.m == 10
A a = 10.0;// a.m == 20

单个参数的函数若是不添加explicit,会发生隐式的类型转换

私有继承与保护继承

私有继承与保护继承的派生类不能称为子类,由于派生类并不能完成父类能作的全部事情

虚继承与多重继承

参考连接:http://www.oschina.net/translate/cpp-virtual-inheritance

类申明的几个技巧

如何让一个类不能被实例化?

将构造函数申明为private或纯虚类(抽象类)

如何让一个类只能在堆上实例化?

将析构函数申明为private

如何让一个类只能在栈上实例化?

重载new运算符为private

如何让一个类的对象不能被复制?

将复制构造函数和赋值函数声明为private,或者声明为 = delete

如何让一个类不能被继承?

加final关键字
其余方法:http://blog.chinaunix.net/uid-26983585-id-4373697.html

四种cast

static_cast

static_cast和C语言里的强制类型转换类似,不过编译时会作类型检查,只有相关的类型才能转换,不然编译错误

dynamic_cast

dynamic_cast在程序运行时根据对象的虚表进行向上或者向下转换。转换指针失败时,返回nullptr,转换引用失败时,抛出异常
然而Google并不建议使用dynamic_cast,参考:http://www.zhihu.com/question/22445339

const_cast

const_cast去除对象的只读属性

reinterpret_cast

reinterpret_cast不作二进制转换,仅仅是从新解释二进制块,经常用在偏底层的操做上,可移植性稍弱

成员函数与对象

class A {
 public:
  static int m;
  int n;
  void func1() { cout << this << ' ' << m << endl; }
  void func2() { cout << this << ' ' << n << endl; }
  static void func3() { cout << m << endl; }
};
int A::m = 10;

A *a = 0;
a->func1();// 0 10
a->func2();// crash
a->func3();// 10
A::func3();// 10

若是对象指针指向错误的地址,对象成员函数仍然能够被调用,可是不能访问非静态成员变量。这里同时也将静态成员函数拿出来比较。
想想,假如成员函数是虚函数,结果还会同样么?

位域

struct A {
  int a:1;
  int b:2;
  int c:3;
};

cout << sizeof(A);// 4

参考连接:http://www.cnblogs.com/bigrabbit/archive/2012/09/20/2695543.html

static的三个域

  • 模块

  • 函数

起到的做用有什么异同

volatile

volatile关键字告诉编译器不要优化被它修饰的变量,这个变量可能在编译器控制范围外发生改变,好比中断或者其余线程
注意下面这个例子

int func(volatile int *p) {
  // return (*p) * (*p); // wrong
  int temp = *p;
  return temp * temp;
}

变量提高

不一样类型的变量参与混合运算时,全部变量将会转换为同一类型,为了避免丢失精度,老是转换为长度更长的变量
在32位机器上,char,short老是转换为int,float老是转换为double
通常状况下,不用关注转换的问题,可是考虑下面一个例子:

signed char a = 0xe0;
unsigned int b = a;
cout << int(a) << ' ' << b;

结果 -32 4294967264
由于在a赋值给b时,a要提高为32位的unsigned int型。然而a是负数,在提高长度时高位将用1来补全,因而a被提高为0xffffffe0。赋值后,b的值为0xffffffe0,因此做为无符号整型输出为4294967264

const成员变量初始化

const成员变量必须在构造函数初始化列表中被初始化。

class A {
 public:
  const int m;
  A(int n) : m(n) {}
};

static const成员变量能够在声明时初始化

class A {
 public:
  static const int m = 0;
  A(int n) {}
};

static成员变量不能在声明时初始化,也不能在构造函数初始化列表中初始化,只能在类外申明并初始化

C++ 11已经支持非静态(static const例外)成员变量声明时初始化,自定义类型不能执行带参数的构造函数

函数调用方式

C和C++程序中,函数的调用有多种方式,能够经过在函数声明时加上__stdcall__cdecl__fastcall来显式指定
不一样的函数调用方式体如今参数传递方式,编译后函数命名方式,函数返回时栈清理方式的不一样。
参考连接:http://www.cnblogs.com/zhangchaoyang/articles/2725189.html

变长参数

简单的说,具备变长参数的函数在调用时(__cdecl方式),编译器按正常的方式将参数从右到左入栈,函数内部再经过指针根据参数类型依次从栈中将参数取出

printf("%c,%d", 'A', 10);举栗
由于参数从右到左进栈且栈是从高地址到低地址生长的,因此此时内存是这样的:

低地址<<|    4 byte   | 1 byte | 4 byte |>>高地址
        |"%c,%d"的地址|  'A'   |   10   |

首先printf函数的第一个参数不是变长参数,这里咱们假设这个参数叫str,它是指向"%c,%d"的指针。有了str,咱们天然就知道了变长参数的起始地址是&str+1,而后再根据"%c,%d",咱们知道了变长参数有两个并且类型分别为charint,因而咱们就能够依次获得这两个变量辣
参考连接:http://www.cnblogs.com/chinazhangjie/archive/2012/08/18/2645475.html

改变const变量的值

经过const_cast能够去除read-only属性,可是编译时编译器仍将使用到const变量的地方直接替换为初始化的那个值,相似于宏

int const a = 1;
int *p = const_cast<int*>(&a);
*p = 2;
cout << a << " " << *p; // 输出: 1 2

如何重写基类虚函数

override,貌似又是C++ 11的关键字

class A {
 public:
  virtual void func(int n);
}

class B : A {
 public:
  virtual void func(int n); // 不要这样,若是参数写错了,至关于声明了重载函数
  void func(int n); // 同上
  void func(int n) override; // 强制重写基类函数,若是参数或返回值与基类虚函数不一致,编译器报错
}

未完......

相关文章
相关标签/搜索