📜  c++ 从构造函数调用覆盖方法 - C++ (1)

📅  最后修改于: 2023-12-03 14:39:54.796000             🧑  作者: Mango

C++ 从构造函数调用覆盖方法

在 C++ 中,构造函数是一个特殊的函数,用于创建对象时初始化对象的数据成员。在某些情况下,构造函数可以调用覆盖(override)方法来实现更复杂的初始化逻辑。本文将介绍 C++ 的构造函数和覆盖方法的基本概念,并给出相关的代码示例。

构造函数的基本概念

构造函数与类的名称相同,没有返回类型,可以有参数。构造函数在对象创建时被调用。如果没有定义构造函数,则编译器会生成一个默认的构造函数。

构造函数的主要作用是为数据成员赋值以及执行其他必要的初始化操作。可以通过初始化列表或构造函数体中的代码来初始化数据成员。

下面是一个简单的示例,展示了如何在构造函数中初始化数据成员:

class Point {
public:
  Point(int x, int y): m_x(x), m_y(y) {}
private:
  int m_x;
  int m_y;
};

在上面的示例代码中,构造函数 Point 接受两个参数 xy,使用初始化列表初始化对象的数据成员 m_xm_y

覆盖方法的基本概念

在 C++ 中,覆盖(override)是指在派生类中重新定义(或实现)基类的虚函数。如果派生类中定义了一个与基类中的虚函数名称、返回类型和参数列表相同的函数,则该函数将覆盖基类的虚函数。

覆盖的主要目的是实现多态性。如果将一个基类指针指向一个派生类对象,然后调用虚函数,将调用派生类中的版本,而不是基类中的版本。

下面是一个简单的示例,展示了如何在派生类中覆盖一个基类的虚函数:

class Shape {
public:
  virtual void draw() const {
    std::cout << "Shape::draw()" << std::endl;
  }
};

class Circle : public Shape {
public:
  void draw() const override {
    std::cout << "Circle::draw()" << std::endl;
  }
};

在上面的示例中,类 Shape 定义了一个虚函数 draw,派生类 Circle 重新定义了该函数,并使用关键字 override 声明它是对基类函数的覆盖。

构造函数中调用覆盖方法

在某些情况下,构造函数可以调用覆盖(override)方法来实现更复杂的初始化逻辑。这是因为,在构造函数中调用虚函数时,将调用正在构造的对象类型的函数版本,而不是派生类的版本。这意味着,即使在派生类中已经覆盖了基类的虚函数,构造函数也可以通过调用基类的虚函数来执行一些预处理或其他初始化操作。

下面是一个简单的示例,展示了如何在构造函数中调用覆盖方法:

class Shape {
public:
  Shape(int x, int y): m_x(x), m_y(y) {
    draw();
  }
  virtual void draw() const {
    std::cout << "Shape::draw() x=" << m_x
              << " y=" << m_y << std::endl;
  }
private:
  int m_x;
  int m_y;
};

class Circle : public Shape {
public:
  Circle(int x, int y, int r): Shape(x, y), m_r(r) {}
  void draw() const override {
    std::cout << "Circle::draw() x=" << m_x
              << " y=" << m_y << " r=" << m_r << std::endl;
  }
private:
  int m_r;
};

在上面的示例中,类 Shape 定义了一个构造函数 Shape,并在构造函数中调用虚函数 draw。派生类 Circle 定义了一个构造函数 Circle,在其中调用基类的构造函数,并初始化自己的数据成员。同时,Circle 重新定义了虚函数 draw,并使用关键字 override 声明。

当创建一个 Circle 对象时,将首先调用 Shape 的构造函数,在其中调用了虚函数 Shape::draw()。此时,Circle 对象还没有完全构造完毕,它的数据成员 m_r 还没有被初始化。然而,由于虚函数的多态性,此时调用的是 Shape::draw() 而不是 Circle::draw()

接下来,返回执行派生类 Circle 的构造函数,其中完成了对数据成员 m_r 的初始化。此时,对象已经完全构造完毕,可以调用虚函数 draw 来绘制圆形。此时,调用的将是派生类 Circle 的版本,因为 Circle 已经完全构造好了。

总结

本文介绍了 C++ 的构造函数和覆盖方法的基本概念,并给出了相关的代码示例。在某些情况下,构造函数可以调用覆盖方法来实现更复杂的初始化逻辑。当调用虚函数时,将调用正在构造的对象类型的函数版本,而不是派生类的版本。这使得构造函数可以在对象完全构造之前执行一些必要的预处理操作。