C++ Object Construction Semantics in Inheritance Hierarchies

Constructor Invocation Sequence

When instantiating an object T obj;, any constructor (trivial or non-trivial) will be invoked.

  1. Members in initialization lists are initialized in declaration order
  2. Members absent from initialization lists with default constructors trigger automatic invocation
  3. Virtual table pointers (vptrs) must be initialized before base constructors
  4. Base class constructors execute in declaration order (independent of initialization list order):
    • Explicit parameters passed if base listed
    • Default constructor invoked if unlisted
    • this pointer adjusted for subsequent base classes
  5. Virtual base constructors initialize depth-first from left to right

Object Composition Example

class Point {
public:
    Point(float xval = 0.0f, float yval = 0.0f);
    virtual ~Point();
private:
    float x_, y_;
};

class LineSegment {
    Point start_, end_;
public:
    LineSegment(const Point& a, const Point& b) 
        : start_(a), end_(b) {}
};

// Constructor expansion
LineSegment* LineSegment::LineSegment(LineSegment* self, 
                                     const Point& a, 
                                     const Point& b) {
    self->start_.Point::Point(a);
    self->end_.Point::Point(b);
    return self;
}

Virtual Inheritance Mechanics

Virtual base classes require specialized handling:

class Point3D : virtual public Point {
public:
    Point3D(float x, float y, float zval) 
        : Point(x, y), z_(zval) {}
private:
    float z_;
};

// Constructor with virtual base control
Point3D* Point3D::Point3D(Point3D* self, bool is_derived,
                          float x, float y, float z) {
    if(is_derived) self->Point::Point();
    self->__vptr_Point3D = __vtable_Point3D;
    self->z_ = z;
    return self;
}

Vptr Initialization Sequence

Virtual pointers initialize after base construction but before user code:

  1. Invoke virtual and direct base constructors
  2. Initialize vptrs to correct virtual tables
  3. Expand member initialization lists
  4. Execute programmer-defined constructor body

Sample expansion:

PVertex* PVertex::Constructor(PVertex* self, bool is_derived,
                             float x, float y, float z) {
    if(is_derived) self->Point::Point();
    self->Vertex3D::Vertex3D(x,y,z);
    self->__vptr_PVertex = __vtable_PVertex;
    // User code executes after vptr setup
    if(debug) 
        cerr << "Size: " << self->__vptr_PVertex[3].func(self);
    return self;
}

Critical considerations:

  • Vptrs must initialize before any virtual function calls
  • Member functions in initialization lists are unsafe for data access
  • Virtual calls in base initialization contexts risk undefined behavior

Thẻ: C++ ObjectModel VirtualInheritance constructor vptr

Đăng vào ngày 30 tháng 6 lúc 21:07