【C++ 面试 - 面向对象】每日 3 题(十)
✍个人博客:Pandaconda-CSDN博客
📣专栏地址:http://t.csdnimg.cn/fYaBd
📚专栏简介:在这个专栏中,我将会分享 C++ 面试中常见的面试题给大家~
❤️如果有收获的话,欢迎点赞👍收藏📁,您的支持就是我创作的最大动力💪
28. C++ 有哪几种构造函数?
C++ 中的构造函数可以分为 4 类:
-
默认构造函数
-
初始化构造函数(有参数)
-
拷贝构造函数
-
移动构造函数(move 和右值引用)
-
委托构造函数
-
转换构造函数
举个例子:
#include <iostream>
using namespace std;class Student{
public:Student(){//默认构造函数,没有参数this->age = 20;this->num = 1000;}; Student(int a, int n):age(a), num(n){}; //初始化构造函数,有参数和参数列表Student(const Student& s){//拷贝构造函数,这里与编译器生成的一致this->age = s.age;this->num = s.num;}; Student(int r){ //转换构造函数,形参是其他类型变量,且只有一个形参this->age = r;this->num = 1002;};~Student(){}
public:int age;int num;
};int main(){Student s1;Student s2(18,1001);int a = 10;Student s3(a);Student s4(s3);printf("s1 age:%d, num:%d\n", s1.age, s1.num);printf("s2 age:%d, num:%d\n", s2.age, s2.num);printf("s3 age:%d, num:%d\n", s3.age, s3.num);printf("s2 age:%d, num:%d\n", s4.age, s4.num);return 0;
}
//运行结果
//s1 age:20, num:1000
//s2 age:18, num:1001
//s3 age:10, num:1002
//s2 age:10, num:1002
-
默认构造函数和初始化构造函数在定义类的对象,完成对象的初始化工作
-
复制构造函数用于复制本类的对象
-
转换构造函数用于将其他类型的变量,隐式转换为本类对象
29. 什么是委托 构造函数?
C++11 引入了委托构造的概念,某个类型的一个构造函数可以委托同类型的另一个构造函数对对象进行初始化。为了描述方便我们称前者为委托构造函数,后者为目标构造函数。委托构造函数会将控制权交给目标构造函数,在目标构造函数执行完之后,再执行委托构造函数的主体。委托构造函数的语法非常简单,只需要在委托构造函数的初始化列表中调用目标构造函数即可。
#include <iostream>
class Data
{
public:int num1;int num2;Data() //目标构造函数{num1 = 100;}Data(int num) : Data() //委托构造函数{ // 委托 Data() 构造函数num2 = num;}
};
void function()
{Data data(99); //首先调用Data() 先给num1复制,然后走到Data(int num) : Data() ,给num2赋值std::cout <<data.num1 << std::endl;std::cout <<data.num2 << std::endl;
}
30. 什 么情况下会调用拷贝构造函数?
-
用类的一个实例化对象去初始化另一个对象的时候
-
函数的参数是类的对象时(非引用传递)
-
函数的返回值是函数体内局部对象的类的对象时,此时虽然发生(Named return Value 优化)NRV 优化,但是由于返回方式是值传递,所以会在返回值的地方调用拷贝构造函数
另:第三种情况在 Linux g++ 下则不会发生拷贝构造函数,不仅如此即使返回局部对象的引用,依然不会发生拷贝构造函数
总结就是:即使发生 NRV 优化的情况下,Linux + g++ 的环境不管是值返回方式还是引用方式返回的方式都不会发生拷贝构造函数,而 Windows + VS2019 在值返回的情况下发生拷贝构造函数,引用返回方式则不发生拷贝构造函数。
在 C++ 编译器发生 NRV 优化,如果是引用返回的形式则不会调用拷贝构造函数,如果是值传递的方式依然会发生拷贝构造函数。
在 VS2019 下进行下述实验:
举个例子:
class A
{
public:A() {};A(const A& a){cout << "copy constructor is called" << endl;};~A() {};
};void useClassA(A a) {}A getClassA()//此时会发生拷贝构造函数的调用,虽然发生NRV优化,但是依然调用拷贝构造函数
{A a;return a;
}A& getClassA2()// VS2019下,此时编辑器会进行(Named return Value优化)NRV优化,不调用拷贝构造函数,如果是引用传递的方式返回当前函数体内生成的对象时,并不发生拷贝构造函数的调用
{A a;return a;
}int main()
{A a1,a3,a4;A a2 = a1; //调用拷贝构造函数,对应情况1useClassA(a1);//调用拷贝构造函数,对应情况2a3 = getClassA();//发生NRV优化,但是值返回,依然会有拷贝构造函数的调用 情况3a4 = getClassA2();//发生NRV优化,且引用返回自身,不会调用return 0;
}
情况 1 比较好理解。
情况 2 的实现过程是,调用函数时先根据传入的实参产生临时对象,再用拷贝构造去初始化这个临时对象,在函数中与形参对应,函数调用结束后析构临时对象。
情况 3 在执行 return 时,理论的执行过程是:产生临时对象,调用拷贝构造函数把返回对象拷贝给临时对象,函数执行完先析构局部变量,再析构临时对象,依然会调用拷贝构造函数。