In C++ it is possible to implicitly call the constructor which can be quite weird and not possible in other languages like Java or Python:

Without explicit

class Cat{
    int age;
    std::string name;
public:
    Cat(int age) : age(age) {};
    Cat(const std::string& name) : name(name) {};
    Cat(int age, const std::string& name) : age(age), name(name) {};
};

int main() {
    Cat cat = 1;
    Cat hansiCat = std::string("Hans");
    Cat manniCat = {5, "Manfred"};
    return 0;
}

This is a valid constructor call. This is implicit conversion. hansiCat needs to be converted to a string first (from const char[]) since implicit conversion converts only once.

This behavior can be prohibited by declaring the constructors explicit.

With explicit

class Cat{
    int age;
    std::string name;
public:
    explicit Cat(int age) : age(age) {};
    explicit Cat(const std::string& name) : name(name) {};
};

int main() {
    Cat cat = 1;
    Cat hansiCat = std::string("Hans");
    return 0;
}

Now this code would throw an error and the constructor needs to be called explicitly.

Special case with initialization lists

class Cat{
    int age;
    std::string name;
public:
    Cat(int age) : age(age) {};
    Cat(const std::string& name) : name(name) {};
    explicit Cat(int age, const std::string& name) : age(age), name(name) {};
};

int main() {
    Cat manniCat = {5, "Manfred"};
    return 0;
}

This will not compile although no warning is shown. However, dropping the = operator still works.

int main() {
    Cat manniCat {5, "Manfred"};
    return 0;
}

Useful implicit conversion

class ScopedPointer {
    Cat* cat;
public:
    ScopedPointer(Cat* cat) : cat(cat) {};
    ~ScopedPointer() { delete cat; }
};

int main() {
    {
        ScopedPointer ptr = new Cat(5);
    }
    // this is the same as
    // ScopedPointer ptr(new Cat(5));
    return 0;
}

Scoped pointer automatically frees the memory once it goes out of scope (like smart pointer)

Categories: