Search code examples
c++inheritancecopy-constructorderived-class

copy constructor for derived class changing base class


Let's assume I have following situation:

class NamedObject{
public:
    NamedObject(const std::string &name):name_{std::move(name)}{}
private: 
    const std::string name_;
}

class Person: public NamedObject{
public:
    Person(const std::string &name, int age): NamedObject(name), age_{age}{}
private:
    int age_;
}

I want to create a "copy constructor" where I copy all members from Person but change the name (for whatever reason).

class Person: public NamedObject{
public:
    Person(const std::string &name, int age): NamedObject(name), age_{age}{}
    Person(const std::string &newName, const Person &other): NamedObject(name){
        age_ = other.age;
    }
private:
    int age_;
}

Now assume I have not only one attribute like age but many attributes and they are changed a lot during development. Is it somehow easily possible to create a function like Person(const std::string &newName, const Person &other) without manually copying all attributes like age_ = other.age;. The idea is that during development I do not have to always recall to change this constructor if I add a new attribute.

Please note that I cannot simply change the name because it is const.


Solution

  • You could define an assignment operator on NamedObject that does nothing. Then you would be able to use *this = other in the "copy constructor":

    class NamedObject{
    public:
        NamedObject(const std::string &name):name_{name}{}
        NamedObject &operator= (const NamedObject &) {
            return *this;
        }
        const std::string name_;
    };
    
    
    class Person: public NamedObject{
    public:
        Person(const std::string &name, int age): NamedObject(name), age_{age}{}
        Person(const std::string &newName, const Person &other): NamedObject(newName){
            *this = other;
        }
        int age_;
    };
    

    Live example: https://onlinegdb.com/rJ4J5oy3M

    Why it works:

    C++ will automatically define a copy assignment operator for eligible classes (check the following link for details on what eligible means). From cppreference:

    If the implicitly-declared copy assignment operator is neither deleted nor trivial, it is defined (that is, a function body is generated and compiled) by the compiler if odr-used. For union types, the implicitly-defined copy assignment copies the object representation (as by std::memmove). For non-union class types (class and struct), the operator performs member-wise copy assignment of the object's bases and non-static members, in their initialization order, using built-in assignment for the scalars and copy assignment operator for class types.

    Thus, for your example the implicitly defined copy assignment operator (the one that is called when we do *this = other;) will be defined as follows:

    • it will use the copy assignment operator of NamedObject to copy the base class (which we defined to do nothing, so it won't copy name_),
    • it will use the copy assignment operator for age_ and any additional member you add to the class.