从超类访问子类?

时间:2014-03-05 18:47:56

标签: c++ virtual subclass superclass

我想知道无论如何我的超类都可以为子类调用函数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 个答案:

答案 0 :(得分: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
   }
};

答案 1 :(得分:2)

简要回答:不,你不能。

长答案:在调用派生类构造函数之前,对象的虚拟表不会被充实。在基类构造函数中,虚拟表指向函数的基类实现。如果基类具有实现,则将调用该函数。如果基类没有实现,则会发生与平台相关的错误/异常。

答案 2 :(得分:0)

你不能用动态多态(使用virtual函数表,也就是作为 vtable )从构造函数中执行此操作,因为在超类尝试调用虚拟的时候方法,只构造了supeclass,并且无法从完全构造的vtable中调用子类initValues()实现。

有两种方法可以解决这个问题:

1。让您的initValues()方法公开,并要求在构建后从客户端调用

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