SyntaxStudy
Sign Up
C++ Class Design: Constructors and Member Initialiser Lists
C++ Beginner 1 min read

Class Design: Constructors and Member Initialiser Lists

A well-designed C++ class separates its interface from its implementation. The interface — declared in a header file — lists public member functions and type aliases. The implementation — defined in a '.cpp' file — provides the function bodies. This separation reduces compilation dependencies and hides internal detail from consumers of the class. Member initialiser lists execute before the constructor body and are mandatory for initialising 'const' data members, reference members, and base class subobjects. Initialising members via the list also avoids the two-step default-construct-then-assign pattern, which can be less efficient for complex types. Members are always initialised in the order they are declared in the class, regardless of list order. The 'explicit' keyword on single-argument constructors prevents implicit conversions that could silently introduce bugs. Without 'explicit', a function accepting a 'Widget' could be called with an 'int' if a converting constructor exists. Marking such constructors 'explicit' forces callers to write the conversion intentionally, improving code clarity and safety.
Example
#include <iostream>
#include <string>

class Rectangle {
public:
    // explicit prevents accidental implicit conversion
    explicit Rectangle(double width, double height)
        : width_(width), height_(height)   // member initialiser list
    {
        if (width_ <= 0 || height_ <= 0)
            throw std::invalid_argument("Dimensions must be positive");
    }

    // const member functions promise not to modify the object
    double width()     const { return width_;          }
    double height()    const { return height_;         }
    double area()      const { return width_ * height_; }
    double perimeter() const { return 2 * (width_ + height_); }

    // Mutators that enforce invariants
    void setWidth(double w) {
        if (w <= 0) throw std::invalid_argument("Width must be positive");
        width_ = w;
    }

    void setHeight(double h) {
        if (h <= 0) throw std::invalid_argument("Height must be positive");
        height_ = h;
    }

    void print() const {
        std::cout << "Rectangle(" << width_ << " x " << height_
                  << ")  area=" << area()
                  << "  perimeter=" << perimeter() << "\n";
    }

private:
    double width_;
    double height_;
};

int main() {
    Rectangle r(5.0, 3.0);
    r.print();
    r.setWidth(10.0);
    r.print();
    return 0;
}