文章目录
- 一、面向对象的基本概念
- 1、面试题--->面向对象的基本原则?
- 2、面试题--->空类会创造哪些成员函数?
- 二、类和结构体
- 1、面试题--->类和结构体的区别?
- 三、成员变量及其初始化
- 四、构造函数和析构函数
- 1、构造函数和析构函数的调用顺序
- 2、面试题--->析构函数为什么要定义为虚函数?
- 3、面试题--->为什么构造函数不能是虚函数?
- 4、面试题--->是否可以把每个函数都声明为虚函数?
- 5、面试题--->析构函数可以是内联函数吗?
- 6、面试题--->析构函数可以抛出异常吗?
- 7、面试题--->构造函数和析构函数为什么不能有返回值?
- 8、面试题--->构造函数无返回值,那如何判断对象是否“构造”成功?
- 9、为什么调用子类的析构函数后会再调用基类的析构函数?
- 五、拷贝构造函数和赋值函数
- 1、面试题--->什么时候会调用拷贝构造函数?
- 2、面试题--->什么时候会调用默认拷贝构造函数?
- 六、深拷贝与浅拷贝
- 七、友元
一、面向对象的基本概念
1、面试题—>面向对象的基本原则?
面向对象的三大原则:继承、封装、多态。
- 继承:子类继承了父类的数据成员和成员函数。
- 封装:隐藏对象的属性和实现细节,仅对外公开接口,控制访问权限(比如private)。
- 多态:同一种方法在子类和父类中有不同的表现,即:一种接口,多种方法。
2、面试题—>空类会创造哪些成员函数?
默认构造函数、析构函数、拷贝构造函数、赋值构造函数。
二、类和结构体
1、面试题—>类和结构体的区别?
类和结构体的区别在于class中的成员默认是private的,而struct默认是public的。struct也可以拥有构造函数和析构函数,以及继承等等。
三、成员变量及其初始化
class test
{
public:
test(int val) : a(val){} // 常量或者引用类型必须在初始化列表中初始化
private:
const int a;
static int b;
}
// 静态数据成员在类外初始化
int test::b = 0;
四、构造函数和析构函数
1、构造函数和析构函数的调用顺序
- 建立对象时,会先调用父类的构造函数再调用子类的构造函数。
- 销毁对象时,会先调用子类的析构函数再调用父类的析构函数。
2、面试题—>析构函数为什么要定义为虚函数?
如果将父类的析构函数定义为虚函数,那么子类的析构函数将自动变为虚函数,在销毁对象时,就会先调用子类的析构函数再调用父类的析构函数。
3、面试题—>为什么构造函数不能是虚函数?
虚函数需要被某个对象调用,而构造函数主要就是用来实例化一个对象,所以虚函数的调用肯定是在构造函数之后的。
4、面试题—>是否可以把每个函数都声明为虚函数?
原则上没有什么问题,但是不建议这样做,因为每声明一个虚函数都会添加到虚函数表中,将所有函数都声明为虚函数会增加系统开销。
5、面试题—>析构函数可以是内联函数吗?
构造函数和析构函数可以是内联函数,但是不建议这样做,因为内联函数只适合体积较小、逻辑简单的函数。
6、面试题—>析构函数可以抛出异常吗?
【Effective C++】不要让异常逃离析构函数!如果析构函数某一处发生异常,那么异常点之后的程序都不会执行,如果在异常点之后还有一些释放资源的操作,那么就会造成资源泄露。
7、面试题—>构造函数和析构函数为什么不能有返回值?
构造函数不需要用户调用,在创建一个对象时会自动执行构造函数,当然也可以直接调用构造函数。构造函数返回的就是这个类的对象this指针,这是不能改变的,默认的。所以构造函数不能指定返回值。
析构函数不带任何参数是因为析构函数仅仅只是负责对类指针成员指向的空间进行释放,不需要有任何参数。也不需要返回值。
8、面试题—>构造函数无返回值,那如何判断对象是否“构造”成功?
- 在C++构造函数中抛出异常,但要注意资源泄漏问题,因为C++拒绝为没有完成构造函数的对象调用析构函数;
- 向C++构造函数多传递一个标志参数,通过该参数来判断对象是否构造成功。
9、为什么调用子类的析构函数后会再调用基类的析构函数?
这是C++的规定,这样做也是为了防止内存泄漏。当在基类的构造函数中申请了资源的时候,派生类因为继承了基类,也就继承了基类的资源,所以析构的时候也要调用基类的析构函数。
五、拷贝构造函数和赋值函数
拷贝构造函数是一种特殊的构造函数,用类的一个对象构造和初始化另一个对象时,会调用拷贝构造函数:
obj (const obj &a);
用类的一个对象给该类的另一个对象赋值时,会调用赋值函数:
obj& operate=(const obj &a);
1、面试题—>什么时候会调用拷贝构造函数?
- 类的对象直接作为函数参数(值传递);
- 类的对象直接作为函数返回值;
- 用类的一个对象构造另一个对象。
2、面试题—>什么时候会调用默认拷贝构造函数?
- 如果用户没有自定义拷贝构造函数,并且在代码中使用到了拷贝构造函数,编译器就会生成默认的拷贝构造函数。但如果用户定义了拷贝构造函数,编译器就不在生成。
- 如果用户定义了一个构造函数,但不是拷贝构造函数,而此时代码中又用到了拷贝构造函数,那编译器也会生成默认的拷贝构造函数。
六、深拷贝与浅拷贝
浅拷贝即用类的对象构造另一个对象或者赋值时,如果用户没有自定义拷贝构造函数或者赋值函数,就会使用默认的拷贝构造函数,当类中有指针变量时,浅拷贝只是拷贝了指针的地址,两个对象仍然指向同一块内存,而深拷贝则会开辟一块新的内存。
浅拷贝的问题在于,析构对象时,同一块内存会被析构两次,因此造成内存错误。
【浅拷贝】:
【深拷贝】:
七、友元
对于类的私有数据成员,只有类的成员函数才能访问,友元的作用在于使得非成员函数可以访问类的私有成员,虽然提高了程序的运行效率,但也破坏了类的封装性。
#include <iostream>
using namespace std;
class A
{
public:
friend void set_show(int x, A &a); // 该函数是友元函数的声明
private:
int data;
};
void set_show(int x, A &a) // 友元函数定义,为了访问类A中的成员
{
a.data = x;
cout << a.data << endl;
}
int main(void)
{
class A a;
set_show(1, a);
return 0;
}