C++面试之语言基础(3)

时间:2021-07-30 08:10:38

51.C++重写和重载重定义区别

  • 重载特征:相同的范围(同一个类),函数名字相同,参数不同
  • 重写(覆盖):派生类函数覆盖基类函数,分别位于基类和派生类中,名字相同,参数相同,基类函数必须有virtual
  • 重定义是指派生类的函数屏蔽了与其同名的基类函数
  • 如果派生类的函数和基类的函数同名,参数不同,此时不管有无virtual,基类的函数被隐藏
  • 如果派生类的函数与基类的函数同名,参数也相同,但基类没有virtual,此时基类的函数被隐藏

52.一个数据成员是否可以既是const又是static,为什么?如果可以,如何初始化。

可以!

static一般在类外初始化,const一般在构造函数里初始化。
既是const又是static就在类外初始化,但要在类外初始化的同时声明为const。

53.构造函数和析构函数的异同点。

构造函数的特点:

  • 构造函数名字与类名相同
  • 构造函数可以有任意的参数,但不能具有返回类型
  • 定义对象时,编译系统自动调用构造函数
  • 构造函数是特殊的成员函数,函数体可以在类内,也可以在类外
  • 构造函数不能像其他成员函数那样被显示调用,它是在定义对象的同时被调用

析构函数的特点:

  • 析构函数名字与类型相同,析构函数前加一个~
  • 析构函数没有参数,也没有返回值,不能被重载,一个类只能有一个析构函数
  • 在撤销对象时,编译系统会自动调用析构函数
  • 析构函数可以是virtual,而构造函数不可以。

54.自动调用拷贝构造函数的几种情形。

  • 拷贝构造函数是用一个已知对象来初始化另一个同类对象。
  • 拷贝构造函数也是类的构造函数,与类名相同,有一个该类对象引用的参数。
  • 若自己不写,则会自动生成一个默认的。
  • 若一个类中有指针,就需要自己写,不能用默认的,因为默认的是地址拷贝

自动调用情况:

  • 当类的一个对象去初始化该类另一个对象时。
  • 如果函数形参是类的对象,调用函数进行形参和实参结合时
  • 如果函数返回值是类对象,函数返回时。

55.类型转换构造函数是什么?

自动调用类型匹配的构造函数,自动将基本数据类型转换成对象。

class Person{
public:
double height;
Person(double h):height(h){}
};

void main()
{
Person p=2.3;//类型转换构造函数,将2.3转换成double调用该构造函数
cout<<p.height<<endl;
}

类型转换函数可以产生自动类型转换匹配,如下:

class Person{
public:
int height;
Person(int h):height(h){}
};
//int的构造函数也可以调用成功。

56.异常处理方式。

步骤:

  1. 程序执行时发生错误
  2. 以一个异常对象记录错误的原因及相关信息
  3. 程序检测到这个错误(读取错误对象)
  4. 程序决定如何处理错误
  5. 错误处理,并在此后恢复或终止程序的执行

57.成员函数和友元函数的区别

  • 成员函数是类定义的一部分,通过特定的对象来调用。成员函数可以隐式访问对象的成员,而无须使用成员操作符
  • 友元函数不是类的组成部分。友元函数不能隐式访问类成员,必须将成员操作符用于参数传递的对象。

58.C++中哪些运算符不能重载

  • .
  • ?:
  • sizeof(不是函数是运算符)
  • ::
  • (指针解引用不可以重载,乘号可以)

59.如何重载前++和后++

  • 前++不带参数,后++带一个(int)以示区分
iCount & operator++(){
    data++;
    return *this;
}
iCount operator++(int)
{
    iCount temp=*this;
    data++;
    return temp;
}

60.请说出STL标准模板库中的几个常用类

P292、 P374

  • vector (顺序容器)可变大小数组。支持快速随机访问。在尾部之外的位置插入或删除元素可能很慢
  • list (顺序容器)双向链表。只支持双向顺序访问,在 list 中任何位置进行 插入/删除 操作速度都很快
  • set (关联容器)关键字即值,即只保存关键字的容器
  • map (关联容器)关联数组,保存 关键字-值 对
  • stack
  • queue

61.函数模板和函数重载的异同

  • 函数重载是指函数名字相同,但是参数类型或者个数不同,顺序不同。
  • 函数模板是指函数算法相同,而参数类型不同。

62.C++中explicit关键字有什么用。

explicit和构造函数一起使用,指明构造函数只能显式调用,目的是为了防止不必要的隐式调用类型转换构造函数。

class Person{
public:
double height;
explicit Person(double h):height(h){}
};

void main()
{
Person p=2.3;//会报错,因为explicit阻止了隐式调用,必须显式调用
Person p2(2.4);//显示调用,可以
cout<<p.height<<endl;
}

63.C++中restrict关键字有什么作用?

  • 是用来优化的;
  • restrict只能修饰指针,修饰的指针是能够访问所指区域的唯一入口,限制多个指针指向同一地址。
  • 如果两个指针指向同一个地址,一个被释放了,另一个就成了野指针。

64.C++中常用的设计模式又哪些?

工厂方法
策略模式
单例模式
迭代器模式
抽象工厂模式
建造者模式
适配器模式
桥接模式
折磨死
解释器模式
命令模式
中介者模式
观察者陌生
状态模式
代理模式

65.写一个单例模式的例子。

其目的是保证一个类仅有一个实例,并提供一个访问它的全局访问点。比如定义常量的类。
将构造函数私有。

class C
{
private:
    C(){};//构造函数私有
    static C * p;
public:
    static C * Get(){
        if(p==NULL)
            p=new C();
        return p;
    }
};
C * C::p==NULL;//static属性类外初始化

void main()
{
    C* p1=C::get();
    C* p2=C::get();
    cout<<(p1==p2)<<endl;//输出true
}

66.面向对象的三大特征。

  • 封装
  • 继承
  • 多态

67.什么是封装

  • 封装是面向对象的特征之一,是对象和类概念的主要特性。
  • 封装,也就是把客观事物封装成抽象的类,并且类可以把自己的数据和方法只让可信的类或者对象操作,对不可信的进行信息隐藏。
  • c++中,public、protected、private就是封装的访问权限说明符。

68.什么是继承

  • 继承可以使现有类的所有功能,并在无需重新编写原来类的情况下对功能进行扩展。
  • c++支持单继承和多继承,也有多级继承。
  • 用public、protected和private修饰继承特性。

69.什么是多态

polymorphisn
- 允许将父对象设置成为一个或更多的他的子对象相等的技术。
- 父对象可以根据当前赋值给它的子对象的特性以不同的方式运作。
- 父类的指针用引用赋子类的值。
- 两种方式,覆盖(重写),重载。
- 覆盖,子类重新定义父类的virtual虚函数。
- 重载,允许存在多个同名函数,但参数列表不同。

70.类和对象的区别。

是一般与个别、抽象与具体、集体与个体的区别。
举个例子即可(人类和张三)

71.c++中的namespace是什么?

命名空间,类似于java中的包
避免在不同程序库中的命名冲突。

72.什么是可重入和不可重入函数?

**可重入性:**reentrant

  • 函数可以由多于一个任务并发使用,而不必担心数据错误,可以在任意时刻被中断,稍后再继续运行不会丢失数据。
  • 不可重入函数不能超过一个任务所共享。

可重入函数:

  • 不为连续的调用持有静态数据
  • 不返回指向静态数据的指针
  • 使用本地数据
  • 如果必须访问全局变量需要利用互斥信号量
  • 不调用不可重入函数

不可重入函数:

  • 使用了静态变量
  • 返回静态变量
  • 调用了不可重入函数
  • 调用了malloc或free
  • 调用了其他标准i/o

总的来说,一个函数使用了未受保护的共享资源,就不可重入。

73.什么时候需要定义一个类的默认构造函数?

合成的默认构造函数只适合非常简单的类,对于一个普通的类来说,必须定义它自己的默认构造函数。
原因有三:

  1. 编译器只会在发现类不包含任何构造函数的情况下才会替我们生成一个默认的构造函数。一旦我们定义了其他的构造函数,除非我们再定义一个默认的构造函数,否则类将没有默认构造函数。
  2. 对于某些类来说,合成的默认构造函数可能执行错误的操作。含有内置类型或复合类型的成员的类应该在类的内部初始化这些成员,或者定义一个自己的默认构造函数。否则,用户在创建类的对象时就可能得到未定义的值
  3. 有的时候编译器不能为某些类合成默认的构造函数。例如,如果类中包含一个其他类类型的成员且这个成员的类型没有默认构造函数,编译器则无法初始化该成员。