C++面试题-面向对象-构造函数和析构函数

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/liubing8609/article/details/86137105

C++面试题-面向对象-构造函数和析构函数

问:构造函数与析构函数是什么?区别是什么?

答:

构造函数:每个类都分别定义了它的对象被初始化的方式,类通过一个或几个特殊的成员函数来控制其对象的初始化过程,这些函数叫做构造函数。构造函数的任务是初始化对象的数据成员,构造函数最重要的作用是创建对象本身。

析构函数:析构函数初始化对象的非static数据成员,还可能做一些其他工作;析构函数释放对象使用的资源,并销毁对象非static数据成员。由于析构函数没有参数,所以它不能被重载。

无论何时一个对象被销毁,就会自动调用其析构函数(以下是销毁的部分):

  1. 变量在离开其作用域时被销毁。
  2. 当一个对象被销毁式,其成员被销毁。
  3. 容器(无论是标准库容器还是数组)被销毁时,其元素被销毁。
  4. 对于动态分配的对象,当对指向它的指针应用delete运算符时被销毁。
  5. 对于临时对象,当创建它的完整表达式结束时被销毁。

区别:

  1. 构造函数可以有参数,所以可以被重载。析构函数没有参数,所以不可以被重载。
  2. 在构造函数中,成员初始化实在函数体执行之前完成的,且按照它们在类中出现的顺序进行初始化。在一个析构函数中,首先执行函数体,然后销毁成员,成员按初始化顺序的逆序销毁。
  3. 在一个构造函数中,不存在类似构造函数中初始化列表的东西来控制成员如何销毁,析构部分是隐式的。成员销毁时发生什么完全依赖于成员的类型。销毁类类型的成员需要执行成员自己的析构函数。内置类型没有析构函数,因此销毁内置类型成员什么也不需要做。

 

问:当子类继承父类,由创建子类的实例到释放时,构造函数和析构函数的调用顺序?

答:当创建子类实例时,先调用父类的构造函数,再调用子类的构造函数。当要释放子类的对象时,先调用子类的析构函数,再调用父类的构造函数来销毁对象。

 

问:什么情况下,把析构函数设置为私有时?

答:自己只调用自己的时候。只允许创建堆对象的时候。

如果在栈上分配空间,类在离开作用域时会调用析构函数释放空间,此时无法调用私有的析构函数。

如果在堆上分配空间,只有在delete时才会调用析构函数。目的是在堆中,可以自由控制对象的生命周期。

 

问:当构造函数设置为私有时,该怎么创建对象?

答:在类里面定义一个static成员函数,在该函数里面调用私有的构造函数。因为静态成员函数就可以不通过对象而直接被调用。

例如:A是类名,Instance是静态函数:

public: 

    static A& Instance() 

    { 

        static A a; 

        return a; 

    } 

int main(int argc, char** argv) 

    A& ra = A::Instance(); 

    ra.Print(); 

还有一个情况是:通常将拷贝构造函数和operator=(赋值操作符重载)声明成private,但是没有实现体。

这个的目的是禁止一个类的外部用户对这个类的对象进行复制动作。

 

问:构造函数和析构函数设置为protected时,作用是什么?

答:如果你不想让外面的用户直接构造一个类(假设这个类的名字为A)的对象,而希望用户只能构造这个类A的子类,那你就可以将类A的构造函数/析构函数声明为protected,而将类A的子类的构造函数/析构函数声明为public

 

问:构造函数可不可以是虚函数?

答:不可以。因为虚函数表是通过初始化才可以有分配的内存,而恰好创建对象初始化数据成员以及创建虚函数表时,是通过构造函数的。如果构造函数是虚函数,那虚函数表是从哪里来呢。

 

问:析构函数是属于虚函数吗?

答:析构函数可以是虚函数,也可以不是虚函数。在类没有继承的时候,可以不设置为虚函数,在子类继承父类的时候,必须设置为虚函数,因为销毁资源时,如果子类的实例没有调用自己的析构函数,就会发生内存泄漏。所以一般情况下,当子类继承了父类,该析构函数是虚函数。

 

问:下面关于CNode类的定义有何错误?

class CNode

{

public:

 CNode *pNext;

 CNode()

 {

  pNext = this;

 }

 ~CNode()

 {

  if (pNext != NULL)

  {

   delete pNext;

   pNext = NULL;

  }

 }

};

答:出现了递归调用。在析构函数中执行“delete pNext”语句时导致递归,因为调用“delete pNext”语句将致使~CNode()析构函数被调用。

分析:析构函数由系统自动调用。有两种情况将导致析构函数被调用:一是对象的作用域消失,二是使用delete运算符释放对象。本题中就是使用delete运算符释放对象。但是本题中是在析构函数中使用delete运算符释放自身,这将导致再次调用析构函数。

 

问:什么是复制构造函数?

答:复制构造函数也称为拷贝构造函数,当函数或方法包含有类对象作为参数时,在函数或方法调用时,将调用复制构造函数构建对象。复制构造函数有固定的语法格式,名称与类同名,参数类型是当前的常量引用类型。

 

问:什么是转换函数?

答:类型转换函数是指用转换构造函数可以将一个指定类型的数据转换为类的对象。

 

问:假定A为一个类的类名,则该类的复制构造函数的函数原型是()。

A.A&(A x);     B.(A x);     C.A(const A &x)      D.A(A*x);

答:C

 

问:复制构造函数在哪些情况下会被自动调用?

答:将类对象作为函数或方法参数时,将调用复制构造函数。此外,如果将类对象作为函数或方法返回值,也将调用复制构造函数。

 

问:请完成下面代码实现main()函数中的类型转换(不能使用运算符重载)?

class CPerson

{

public:

 int m_nAge;

 CPerson()

 {

  m_nAge = 0;

 }

};

void main(void)

{

 CPerson person = 10;//将该语句合法化

}

答:通过构造函数来实现类型转换。修改CPerson类的构造函数,使其包含一个整数作为参数。例如:

CPerson(int Age)

{

m_nAge=Age;

}

 

问:C++中的explicit关键字有何作用?

答:explicit关键字的作用是禁止将构造函数作为转换函数。例如,如果一个类的构造函数中只包含一个整数参数,在构造函数前使用explicit关键字可以阻止像"CPerson person=10;”这样的语句执行。

 

问:比如类为A,请举例写出利用默认构造函数和重载构造函数创建对象的语句。

答:

默认构造函数:A a;

重载函数:A a(1,2);

猜你喜欢

转载自blog.csdn.net/liubing8609/article/details/86137105
今日推荐