0

I am trying to create a base and a derived class with a const member that has to be initialized:

class baseClan
{
public:
    baseClan(const string firstName)
    :
    fullName(createFullName(firstName))
    {}
private:
    const string lastName = "Smith";
    const string fullName;
    virtual const string createFullName(string firstName) { return firstName + " " + lastName ; }
}

How do I implement the derived class so that it can use a differently implemented createFullName? I am looking at this link https://isocpp.org/wiki/faq/strange-inheritance#calling-virtuals-from-ctor-idiom but it seems like I'm stuck between a rock and a hard place: the first approach it proposes (using init) is not applicable to initialization list; while in the second approach it is explicitly stated that it cannot handle the case where we need to access the instance data declared in Derived.

PF Chang
  • 47
  • 6
  • 1
    I don't see the declaration of `fullName`. Please post a [mcve]. – R Sahu Mar 16 '20 at 05:28
  • You can't do that, and you need to rethink your approach. It's very difficult to suggest a working solution without knowing more about the real problem you're trying to solve. (This looks like a question that will acquire more requirements with each suggested solution.) – molbdnilo Mar 16 '20 at 05:59
  • I need a string to be used as the id of the instance, so I was thinking to initialize the string during construction. I suppose I can live with not implementing the function in the base class because the base class is pure virtual, but it's not ideal... – PF Chang Mar 16 '20 at 06:10
  • Do you really have to make class fields constant? – Grandbrain Mar 16 '20 at 06:13
  • Not the end of the world if not const, I can live with that – PF Chang Mar 16 '20 at 07:55
  • Then why not initialize them in derived classes? Or, you can even keep data fields as `const`, make base constructor to accept parameters to initialize them, and then in derived class you pass the necessary arguments (even, perhaps, from virtual functions) to the base constructor using the initialization list. I will complement my answer with an example. – Grandbrain Mar 16 '20 at 09:00

1 Answers1

0

Calling virtual functions from a constructor or destructor is dangerous and should be avoided whenever possible. All C++ implementations should call the version of the function defined at the level of the hierarchy in the current constructor and no further.

Virtual functions in the constructors work differently. When creating an object of an derived class, the object of the base class is created first, which means that the derived class has not yet been created and the virtual function has not yet been overrided.

I think that all possible approaches to this problem are already described by the link that you provided (C++ FAQ). But I highly recommend rethinking your code.

You can apply a slightly different approach. You can make base constructor to accept parameters to initialize data fields, and then in derived class you pass the necessary arguments (even, perhaps, from virtual functions) to the base constructor using the initialization list. For example:

class A {
public:
    A(int a, int b) : a_(a), b_(b) { }
    virtual int getA() const = 0;
    virtual int getB() const = 0;
    void print() { cout << a_ << ' ' << b_ << endl; }
private:
    const int a_ = 0;
    const int b_ = 0;
};

class B : public A {
public:
    B() : A(getA(), getB()) { }
    int getA() const override { return 1; }
    int getB() const override { return 2; }
};

int main() {
    B b;
    b.print();
    return 0;
}
Grandbrain
  • 409
  • 3
  • 11