某日二师兄加入 XXX 科技公司的 C ++ 工程师开发岗位第 29 面:
面试官:什么是构造函数?
二师兄:构造函数是一种非凡的成员函数,用于创立和初始化类的对象。构造函数的名称与类的名称雷同,并且没有返回类型。构造函数在对象被创立时主动调用。
struct Foo
{Foo(int v):val(i){} // 构造函数
private:
int val;
};
面试官:什么是默认构造函数?什么状况下默认构造函数会被创立?
二师兄:没有任何参数的构造函数(所有参数都要默认参数的构造函数也是)。个别定义类时没有显式的申明任何构造函数,默认构造函数会被编译器主动创立。
struct Foo
{
private:
int val;
}; // 此时默认构造函数会被创立
二师兄:当然就算为类自定义了构造函数,咱们也能够通过
Foo()=default
为类显式定义一个默认构造函数。面试官:什么是构造函数初始值列表?
二师兄:是为了初始化成员变量所传入的参数列表:
class Foo
{
public:
Foo(int i, long l):ival_(i),lval_(l){} // 初始值列表
private:
int ival_;
long lval_;
};
面试官:下面的构造函数和以下的构造函数有什么区别?
Foo(int i, long l)
{
ival_ = i;
lval_ = l;
}
二师兄:这是初始化与赋值的区别。这段代码中的
ival_
和 lval_
先被默认初始化,而后被赋值。而初始化列表是间接初始化,少了一步赋值。面试官:如果把构造函数写成
Foo(int i, long l):lval(l),ival_(i){}
会有什么问题吗?二师兄:成员初始化的程序尽量要和定义的程序保持一致。如上面的代码,就是未定义的:
class Foo
{
public:
Foo(int i):jval_(i),ival_(jval_){} // 未定义的行为,因为 ival 先被初始化,这时候 jval 是未定义的
private:
int ival_;
int jval_;
};
面试官:什么是委托构造函数?
二师兄:构造函数在结构对象的时候把一部分工作委托给其余构造函数进行结构,这是 C ++11 引入的新个性:
class Foo
{
public:
Foo(int i, long l):ival_(i),lval_(l){}
Foo(int i):Foo(i,0){} // 委托给 Foo(int i, long l)
private:
int ival_;
long lval_;
};
面试官:如果构造函数没有初始化任何成员变量,应用这个构造函数会产生什么?
二师兄:成员变量将会被 默认初始化。
面试官:什么是默认初始化?
二师兄:如果是内置类型(如
bool
、int
、double
),将不被初始化,如果是类类型,将执行类类型的的默认构造函数初始化变量。如果类类型的默认构造函数是删除的(=delete
)或定义了其余构造函数然而没有定义默认构造函数的,将不能通过编译。二师兄:类类型的初始化时一个循环的过程,如果类类型中有类类型成员,初始化形式和以上形容的统一。
struct Foo{int a;}
struct Goo
{
int b;
Foo f;
};
Goo g; // 此 g.b 是默认初始化,值不确定。Foo 中的 a 也是默认初始化,所以 g.f.a 的值也是不确定的。
面试官:能够应用
virtual
润饰构造函数吗?二师兄:不能够,因为构造函数在对象结构阶段调用,虚表尚未建设,所以无奈调用虚函数实现多态。
面试官:能够应用
const
润饰构造函数吗?二师兄:不能够,因为构造函数须要初始化成员变量,这与
const
润饰成员函数的意义相悖。面试官:能够应用
constexpr
润饰构造函数吗?二师兄:能够。这表明类的对象能够在编译器结构。咱们所相熟的
std::array
的构造函数在 C ++20 下就是constexpr
的。面试官:什么状况下会将一个类的构造函数定义为公有的?
二师兄:个别不心愿间接通过类型定义对象,如 C ++ 的单例模式:
class Singleton
{
public:
static Singleton& Instance()
{
static Singleton instance;
return instance;
}
Singleton(const Singleton&) = delete;
Singleton(Singleton&&) = delete;
Singleton& operator=(const Singleton&) = delete;
Singleton& operator=(Singleton&&) = delete;
private:
Singleton() = default;
~Singleton() = default;};
Singleton s; // 编译失败
Singleton& s = Singleton::Instance(); // 编译胜利
面试官:最初一个问题,你知申明、定义、初始化、赋值的区别吗?
二师兄:申明是通知编译器这里有个符号,但不分配内存。定义通知编译器,这里有个符号,要调配一块内存给它。初始化时在分配内存的时候给它一个初始值。赋值是将这块内存原来的值擦除,给它填入一个新值。
面试官:好的,明天的面试完结了,请回去等告诉吧。
C++ 类的构造函数的根本考点都在这里了,小伙伴本要了解这些设计及设计背地的取舍,面对面试官的拷问能力对答如流哦。
好了,明天的面试到这里就完结了,让咱们期待今天面试官和二师兄的体现吧~
关注我,带你 21 天“精通”C++!(狗头)