Доступ к подклассам из суперкласса?

Мне было интересно, если есть так или иначе, что мой суперкласс может вызвать функцию initValues ​​() для подкласса без необходимости переопределить конструктор?

Вот код:

#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

Затем я создаю переменную следующим образом:
Vector3 vec;

И тогда я хотел бы
initValues ​​()
метод подкласса Vector3 для вызова.

Это возможно?

3

Решение

Краткий ответ: нет, вы не можете.

Длинный ответ: виртуальная таблица объекта не раскрывается, пока не будет вызван конструктор производного класса. В конструкторе базового класса виртуальная таблица указывает на реализацию функции базового класса. Если базовый класс имеет реализацию, эта функция будет вызвана. Если базовый класс не имеет реализации, возникает ошибка / исключение, зависящее от платформы.

2

Другие решения

Если вы хотите назвать оба суперкласса initValues() а затем подкласс initValues() вам нужно будет явно позвонить Vector::initValues() от Vector3::initValues() поскольку динамическая диспетчеризация всегда будет вызывать более специализированную версию метода:

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

Если вы действительно хотите сохранить порядок в нужном вам порядке, вам потребуется второй метод:

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

virtual void specificInitValues() = 0;
};

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

Вы не можете сделать это с динамическим полиморфизмом (используя virtual таблица функций, ака. как виртуальные таблицы) из конструктора, потому что в момент, когда суперкласс пытается вызвать виртуальный метод, только суперкласс построен, а подкласс initValues() реализация не может быть вызвана из полностью построенного vtable.

Есть два способа преодолеть эту проблему:

1. Сделай свой initValues() метод public и требует, чтобы он вызывался от клиентов после создания

2. Вы можете сделать, чтобы добиться такого поведения, вместо этого использовать статический полиморфизм:

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;
}
}

Последний способ может потребовать дополнительного разграничения абстрактного интерфейса, реализованного в суперклассе, для его разумного использования в контексте, который не знает о VectorSubи не нужно.

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;
};
0
По вопросам рекламы [email protected]