构造函数和析构函数

本文最后更新于:1 年前

constructor

构造函数

cpp的构造函数有很多写法,比如无参和有参的写法:

1
2
3
4
5
6
7
8
class A
{
public:
A() : a(1) {}
A(int x) : a(x) {}
protected:
int a;
}

嫌麻烦的话,还可以这么写:

1
2
3
4
5
6
7
class A
{
public:
A(int x = 1) : a(x) {}
protected:
int a;
}

这样的话,如果初始化A对象无参数传入

1
A a1;

那么a1.a的值默认为1;

如果是有参数传入

1
A a1(999)

那么此时a1.a的值为999。

如何写子类的构造函数

1
2
3
4
5
6
7
class B : public A
{
protected:
int b;
public:
B(int x = 1, int y = 2) : A(x), b(y) {}
}

派生类不会继承基类的

  • 构造、析构、拷贝构造函数
  • 重载运算符
  • 友元函数

destructor

析构函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
class Base
{
public:
Base(int _a = 0) : a(_a) {}
~Base() {std::cout << "Base destructor" << std::endl;} // 最好前面加上virtual
protected:
int a;
}

class Derived : public Base
{
public:
Derived(int _b = 0) : b(_b) {}
~Derived() {std::cout << "Derived destructor" << std::endl}
protected:
int b;
}
  • 需要注意的是,如果用指向基类的指针操作派生类 Derived ,当其生命周期结束后,如果基类析构 不是 virtual function ,只有基类的析构函数被调用,可能会造成派生类的资源没有被释放

    为什么基类的析构函数是虚函数?

    在实现多态时,当用基类操作派生类,在析构时防止只析构基类而不析构派生类的状况发生

  • 所以务必将 destructor 定义为 virtual function ,尤其是当成员变量有指针时

    1
    virtual ~Base() {do something}
  • 当父类的 destructor 为 virtual function 时,派生类的 destructor 默认为 vritual function ,不过最好还是在派生类的 destructor 前加上 virtual

  • 有没有必要将 destructor 声明为纯虚函数?(当有纯虚函数时,该类为抽象基类,不能实例化对象)

    1
    virtual ~Base = 0;

    答案是能够,但要看情况

    那么这样实现的目的是什么呢?当然是避免实例化,比如Animal是不应该被实例化的,只有Dog或者Cat被实例化才有具体意义,为了避免Animal实例化,但又因为Animal没有其他的纯虚函数,所以可以将Animal的析构声明为pure virtual function

    但由于派生类不可能来实现基类的析构函数,所以基类析构函数尽管能够标为纯虚,可是仍必须实现析构函数,否则派生类无法继承。也无法编译通过

    因为子类调用自己的虚析构函数前,要调用父类的析构函数,而当父类的析构为纯虚函数,如果没有在类外定义函数体,编译会失败,提示没有父类的析构函数

    可以为纯虚函数定义一个空的函数体,链接器就能找到基类的虚构函数了

    1
    2
    3
    4
    5
    6
    7
    8
    9
    class Base
    {
    public:
    Base(int _a = 0) : a(_a) {}
    virtual ~Base() = 0;
    protected:
    int a;
    }
    Base::~Base() {}

本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!