面试题总结

1.int f(int a)能重载void f(int a)吗?重载是在编译期还是运行期?

答:不能重载,因为调用时不能指定类型信息,编译器不知道你要调用哪个函数。 重载是在编译器,虚函数多态(重写)才是在运行期。

2.拷贝构造函数作用及用途?什么时候需要自定义拷贝构造函数?

答:(1)在C++中,有下面三种对象需要拷贝的情况:

a.一个对象以值传递的方式传入函数体

b.一个对象以值传递的方式从函数返回

c.一个对象需要通过另一个对象进行初始化

以上的情况就需要拷贝构造函数的调用

(2)当类中数据成员需要动态分配存储空间时,不可以依赖default copy constructor 。当default copy constructor被编译器需要而和成时,将执行default memberwise copy 语义。

此时如果类中有动态分配的存储空间时,将会发生惨重的灾情。

3.构造函数可以调用虚函数吗?

答:不能,语法上通过,语义上有问题。 
derived class对象内的base class成分会在derived class自身构造之前构造完毕。因此,在base class的构造函数中执行的virtual函数将会是base class的版本,决不会是derived class的版本。 
即使目前确实正在构造derived class。

4.c++11 有哪些改进?有哪些东西 ?

答: lambda 线程库  智能指针 auto

5.如果实现一个不能在对上分配的类?如果实现一个不能被继承的类?

答:在堆上分配就需要用到new操作符,重载new操作符并将其放于private内。  这个用到C++ 11新关键字final

class B final {
public:
    B(int a) {
    }
};

  现在就不能继承了

6.引用和指针右什么区别?

答:

(1)定义一个指针变量编译器会为它分配内存,而引用不占用任何内存;

(2)引用必须在定义时被初始化,指针不必;

(3)不存在指向空值的引用,但存在指向空值的指针。

7.函数参数传递中值传递、地址传递、引用传递有什么区别?

答:

(1) 值传递,会为形参重新分配内存空间,将实参的值拷贝给形参,形参的值不会影响实参的值,函数调用结束后形参被释放;

(2) 引用传递,不会为形参重新分配内存空间,形参只是实参的别名,形参的改变会影响实参的值,函数调用结束后形参不会被释放;

(3) 地址传递,形参为指针变量,将实参的地址传递给函数,可以在函数中改变实参的值,调用时为形参指针变量分配内存,结束时释放指针变量。

8.static关键字有什么作用?

答:

(1)函数体内static变量的作用范围为该函数体,不同于auto变量,该变量的内存只被分配一次,因此其值在下次调用时维持上次的值;

(2)在模块内的static全局变量可以被模块内所用函数调用,但不能被模块外其他函数访问;

(3)在模块内的static函数只能被这一模块内的其他函数调用,这个函数的使用范围被限制在声明它的模块内;

(4)在类中的static成员变量属于整个类拥有,对类的对象只有一份拷贝;

(5)在类中的static成员函数属于整个类拥有,这个函数不接收this指针,因而只能访问static成员变量。

9.const关键字有什么作用?

答:

(1)阻止一个变量被改变,可以使用const关键字。在定义该const变量时,通常需要对它初始化,因为以后就没机会改变它了;

(2)对指针来说,可以指定指针本身为const,也可指定指针所指的数据为const,或二者同时指定为const;

(3) 在一个函数声明中,const可以修饰形参,表明它是一个输入参数,在函数内部不能改变其值;

(4) 对于类的成员函数,若指定其为const类型,则表明其是一个常函数,不能修改类的成员变量;

(5) 对于类的成员函数,有时候必须指定其返回值为const类型,以使得其返回值不为左值。

10 .链表和数组的区别在哪里?

(1) 链表和数组都可以叫线性表,数组又叫顺序表,主要区别在于,顺序表是在内存中开辟一段连续的空间来存储数据,而链表是靠指针来连接多块不连续的空间,在逻辑上形成一片连续的空间来存储数据;

(2) 数组要求空间连续,占用总空间小,链表不要求空间连续,占用总空间大;

(3) 数组方便排序和查找,但删除和插入较慢;链表方便删除和插入,但查找较慢,不方便排序。

11.进程和线程的差别?

答:

线程是指进程内的一个执行单元,也是进程内的可调度实体。线程与进程的区别:

(1)调度:线程作为调度和分配的基本单位,进程作为拥有资源的基本单位;

(2)并发性:不仅进程之间可以并发执行,同一个进程的多个线程也可以并发执行;

(3)拥有资源:进程是拥有资源的一个独立单元,线程不拥有系统资源但可以访问隶属于进程的资源;

(4)系统开销:在创建或撤销进程时,由于系统都要为之分配和回收资源,导致系统的开销明显大于创建或撤销线程时的开销。

12.C++重写、重载、重定义的区别?

(1)成员函数重载特征:

a.相同的范围,在同一个类

b.函数名字相同

c.参数不同

(2)重写(覆盖)是指派生类函数覆盖基类函数,特征是:

a.不同的范围,分别位于基类和派生类中

b.函数的名字相同

c.参数相同

d.基类函数必须有virtual关键字

(3)重定义(隐藏)是指派生类的函数屏蔽了与其同名的基类函数,规则如下:

a.如果派生类的函数和基类的函数同名,但是参数不同,此时不管有无virtual,基类的函数被隐藏;

b.如果派生类的函数与基类的函数同名,并且参数也相同,但是基类函数没有virtual关键字,此时基类函数被隐藏。

13.一个数据成员是否可以既是const又是static,如果不行,为什么?

(1)一个数据成员可以既是const又是static,表示为静态常量;

(2)常量一般在构造函数后初始化;

(3)静态成员一般在类外初始化;

(4)静态常量在类外初始化,但要在类外初始化的同时声明为const。

14.构造函数与析构函数的异同点?

答:

1.构造函数有如下特点:

(1)构造函数的名字必须与类名相同;

(2)构造函数可以有任意类型的参数,但不能有返回类型;

(3)定义对象时,编译系统会自动调用构造函数;

(4)构造函数是特殊的成员函数,函数体可以在类体内也可以在类体外;

(5)构造函数被声明为公有函数,但它不能像其他成员函数那样被显式调用,它是在定义对象的同时被调用的。

2.析构函数有如下特点:

(1)析构函数的名字必须与类名相同,但它前面必须加一个波浪号;

(2)析构函数没有参数,也没有返回值,而且不能被重载,因此在一个类中只能有一个析构函数;

(3)当撤销对象时,编译系统会自动调用析构函数;

(4)析构函数可以是virtual,而构造函数不能是虚函数。

 

15.简述C++异常处理方式?

答:

一个典型的C++异常处理包含以下几个步骤:

(1)程序执行时发生错误;

(2)以一个异常对象(最简单是一个整数)记录错误的原因及相关信息;

(3)程序监测到这个错误(读取异常对象);

(4)程序决定如何处理错误;

(5)进行错误处理,并在此后恢复/终止程序的执行。

 

16.成员函数和友元函数的区别?

(1)成员函数是类定义的一部分,通过特定的对象来调用。成员函数既可以隐式访问调用对象的成员,而无须使用成员操作符;

(2)友元函数不是类的组成部分,因此被称为直接函数调用。友元函数不能隐式访问类成员,而必须将成员操作符用于作为参数传递的对象。

 

17.函数模板与函数重载的异同?

(1)函数的重载是指定义了几个名字相同,但参数的类型或参数的个数不同的函数;

(2)模板函数是指的几个函数的具体算法相同,而参数类型不同的函数;

(3)模板函数可以减少重载函数,但也可能引发错误。

 

18.面向对象的三大特征是什么?

面向对象的三个基本特征:封装、继承、多态。

 

19.什么是封装?

(1)封装是面向对象的特征之一,是对象和类概念的主要特性;

(2)封装,也就是把客观事物封装成抽象的类,并且类可以把自己的数据和方法只让可信的类或者对象操作,对不可信的进行信息隐藏;

(3)在C++中类中成员的属性有:public、protected、private,这三个属性的访问权限依次降低。

 

20.什么是继承?

(1)继承是指:可以使用现有类的所有功能,并在无须重新编写原来的类的情况下对这些功能进行扩展;

(2)通过继承创建的类称为“子类”或“派生类”;

(3)被继承的类称为“基类”、“父类”或“超类”;

(4)在某些OOP语言中,一个子类可以继承多个基类,但是一般情况下,一个子类只能有一个基类,要实现多重继承,可以通过多级继承来实现;

(5)C++中可以用public、protected、private来修饰继承特性。

 

21.什么是多态?

(1)多态性:允许将父类对象设置为和一个或更多的它的子对象相等的技术,赋值之后,父对象可以根据当前赋值给它的子对象的特性以不同的方式运作。简单地说,允许将子类类型的指针赋值给父类型的指针;

(2)实现多态的两种方式:覆盖、重载;

(3)覆盖:子类重新定义父类的虚函数;

(4)重载:允许存在多个同名函数,而这些函数的参数表不同。

 

22.不可以同时用const和static修饰成员函数。

C++编译器在实现const的成员函数的时候为了确保该函数不能修改类的实例的状态,会在函数中添加一个隐式的参数const this*。但当一个成员为static的时候,该函数是没有this指针的。也就是说此时const的用法和static是冲突的。我们也可以这样理解:两者的语意是矛盾的。static的作用是表示该函数只作用在类型的静态变量上,与类的实例没有关系;而const的作用是确保函数不能修改类的实例的状态,与类型的静态变量没有关系。因此不能同时用它们。

23.类型安全以及C++中的类型转换?

四种类型转换:

  • static_cast <T*> (content)  静态转换.在编译期间处理,可以实现C++中内置基本数据类型之间的相互转换。如果涉及到类的话,static_cast只能在有相互联系的类型中进行相互转换,不一定包含虚函数。
  • dynamic_cast<T*>(content) 动态类型转换;也是向下安全转型;是在运行的时候执行;基类中一定要有虚函数,否则编译不通过。在类层次间进行上行转换时(如派生类指针转为基类指针),dynamic_cast和static_cast的效果是一样的。在进行下行转换时(如基类指针转为派生类指针),dynamic_cast具有类型检查的功能,比static_cast更安全。
  • const_cast<T*>(content) 去常转换;编译时执行;
  • reinterpret_cast<T*>(content) 重解释类型转换;

24 C语言和C++有什么区别? 
    C语言是结构化的编程语言,它是面向过程的,而C++是面向对象的。 
    封装:将数据和函数等集合在一个单元中(即类)。被封装的类通常称为抽象数据类型。封装的意义在于保护或者防止代码(数据)被我们无意中破坏。 
    继承:继承主要实现重用代码,节省开发时间。它可以使用现有类的所有功能,并在无需重新编写原来的类的情况下对这些功能进行扩展。 
    多态:同一操作作用于不同的对象,可以有不同的解释,产生不同的执行结果。在运行时,可以通过指向派生类的基类指针,来调用实现派生类中的方法。有编译时多态和运行时多态。

 

25.如何实现类对象只能静态分配或动态分配?

C++中建立类的对象有两种方式:
(1)静态建立,例如 A a;
     静态建立一个类对象,就是由编译器为对象在栈空间中分配内存。使用这种方法,是直接调用类的构造函数。
(2)动态建立,例如 A* p = new A();
     动态建立一个类对象,就是使用new运算符为对象在堆空间中分配内存。这个过程分为两步:第一步执行operator new( )函数,在堆空间中搜索一块内存并进行分配;第二步调用类的构造函数构造对象。这种方法是间接调用类的构造函数。

只能动态分配:  

      其实,编译器在为类对象分配栈空间时,会先检查类的析构函数的访问性(其实不光是析构函数,只要是非静态的函数,编译器都会进行检查)。如果类的析构函数在类外部无法访问,则编译器拒绝在栈空间上为类对象分配内存。因此,可以将析构函数设为private,这样就无法在栈上建立类对象了。但是为了子类可以继承,最好设置成protected。
class A  
{  
protected:  
     A(){}  
     ~A(){}  
public:  
     static A* create(){return new A();}  
     void destory(){delete this;}  
};  

  

只能静态分配:

    只有使用new运算符,对象才会被建立在堆上。因此只要限制new运算符就可以实现类对象只能建立在栈上。可以将new运算符设为私有。

 

class A  
{  
private:  
     void* operator new(size_t t){}            //注意函数的第一个参数和返回值都是固定的  
     void  operator delete(void* ptr)()        //重载了new就需要重载delete  
public:  
     A(){}  
     ~A(){}  
};  

26auto_ptr类与shared_ptr类?

从c++11开始, auto_ptr已经被标记为弃用, 常见的替代品为shared_ptr。shared_ptr的不同之处在于引用计数, 在复制(或赋值)时不会像auto_ptr那样直接转移所有权。 两者都是模板类,却可以像指针一样去使用。只是在指针上面的一层封装。

      auto_ptr实际也是一种类, 拥有自己的析构函数, 生命周期结束时能自动释放资源,正因为能自动释放资源, 特别适合在单个函数内代替new/delete的调用, 不用自己调用delete,也不用担心意外退出造成内存的泄漏。

   atuo_ptr的缺陷:

 

  •  auto_ptr不能共享所有权,即不要让两个auto_ptr指向同一个对象(因为它采用的是转移语义的拷贝,原指针会变为NULL)。
  •  auto_ptr不能管理对象数组(因为它内部的析构函数调用的是delete而不是delete[])。
  •  auto_ptr不能作为容器对象,STL容器中的元素经常要支持拷贝,赋值等操作,在这过程中auto_ptr会传递所有权。
  • shared_ptr 使用引用计数的方式来实现对指针资源的管理。同一个指针资源,可以被多个 shared_ptr 对象所拥有,直到最后一个 shared_ptr 对象析构时才释放所管理的对象资源。

          可以说,shared_ptr 是最智能的智能指针,因为其特点最接近原始的指针。不仅能够自由的赋值和拷贝,而且可以安全的用在标准容器中。

27. C++是不是类型安全的?

答:不是,两个不同类型的指针之间可以可以强制转换(reinterpret cast)

 

 

posted @ 2018-09-08 16:51  cs_wu  阅读(596)  评论(0编辑  收藏  举报