Question

I was wondering if there is anyway that my superclass can call the function initValues() for the subclass without having to override the constructor?

Here's the code:

#ifndef VECTOR_MATH_H
#define VECTOR_MATH_H

#include "GL\glew.h"

#include <iostream>

namespace Math3d
{

class Vector
{
public:
    Vector(int length=2) : v(new float[length]) { initValues(); }
    ~Vector() { delete[] v; }
protected:
    virtual void initValues()
    {
        std::cout << "Vector" << std::endl;
    }
    float* v;
};

class Vector3 : public Vector
{
public:
protected:
    void initValues()
    {
        std::cout << "Vector3" << std::endl;
    }
};

}

#endif

I then create a variable like this: Vector3 vec;

And then I would like the initValues() method of the subclass, Vector3 to be called.

Is this possible?

Was it helpful?

Solution

Brief answer: No, you can't.

Long answer: The virtual table of the object is not fleshed out until the derived class constructor has been called. In the base class constructor, the virtual table points to the base class implementation of the function. If the base class has an implementation, that function will be called. If the base class does not have an implementation, a platform dependent error/exception will occur.

OTHER TIPS

If you want to call both the superclass initValues() and then the subclass initValues() you will need to explicitly call Vector::initValues() from Vector3::initValues() since dynamic dispatch will call always the more specialized version of the method:

void Vector3::initValues() {
  Vector::initValues();
  other specific code;
}

If you really want to keep things in the order you want then you will require a second method:

class Vector {
  protected:
    void initValues() {
      // common init
      specificInitValues();
    }

    virtual void specificInitValues() = 0;
};

class Vector3 : public Vector {
  protected:
   virtual void specificInitValues() override {
     // specific init
   }
};

You can't do this with dynamic polymorphism (using a virtual function table, aka. as vtable) from the constructor, because at the point the superclass tries to call the virtual method, only the supeclass is constructed yet, and the subclass initValues() implementation can't be called from the fully constructed vtable.

There are two ways to overcome this issue:

1. Make your initValues() method public, and require it to be called from clients after construction

2. You could do to achieve this behavior, is to use static polymorphism instead:

template<class Derived>
class VectorSuper
{
public:
    VectorSuper(int length=2) 
    : v(new float[length]) 
    { 
        static_cast<Derived*>(this)->initValues(); 
    }
    ~VectorSuper() { delete[] v; }
protected:
    void initValues() // Note, no virtual
    {
        std::cout << "VectorSuper" << std::endl;
    }
    float* v;
};

class VectorSub
: public VectorSuper<VectorSub>
{
protected:
    void initValues() // Note, no virtual
    {
        VectorSuper<VectorSub>::initValues();
        std::cout << "VectorSub" << std::endl;
    }
}

The latter way, might inquire some further distinction of an abstract interface implemented in the superclass, to be reasonably usable in a context that doesn't know about VectorSub, and doesn't need to.

class AbstractVector
{
public:
    virtual ~AbstractVector() = 0;
    // example interface
    virtual float operator[](int index) const = 0;
};

template<class Derived>
class VectorSuper
: public AbstractVector
{
public:
    VectorSuper(int length_=2) 
    : length(length_), v(new float[length]) 
    { 
        static_cast<Derived*>(this)->initValues(); 
    }
    ~VectorSuper() { delete[] v; }

    virtual float operator[](int index) const
    {
        if(index >= length || index < 0)
        {
            throw std::invalid_argument("index");
        }
        return v[index];
    }
protected:
    // ... as before

    int length; // Remember length additionally!
    float* v;
};
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top