【问题标题】:Undefined Reference to vtable with abstract class未定义对具有抽象类的 vtable 的引用
【发布时间】:2020-12-11 09:29:24
【问题描述】:

在构建我的 C++ 程序时,我收到了错误消息。

对 vtable 的未定义引用

我有两个虚拟抽象类被调用,如果我做错了什么,我无法弄清楚我做错了什么。 我从从抽象类继承的两个类中都收到错误。 我的抽象类是

对 `vtable for hittable_list' 的未定义引用

对 `vtable for sphere' 的未定义引用

hittable.h

     #ifndef HITTABLE_H
        #define HITTABLE_H
    
    #include "ray.h"
    
    struct hit_record {
        hit_record() {}
        ~hit_record() {}
        float t;
        vecfloat p;
        vecfloat normal;
        float MAXFLOAT = 100.0; 
}; 

    //Abstract Class containing Sphere and hittablelist 
    class hittable 
    {
     public:
            virtual ~hittable() = 0;
        
            virtual bool hit(const ray &r, float t_min, float t_max, hit_record &rec) const = 0;
 };
        
        #endif

继承自我的抽象类的类是。

sphere.h

 #ifndef SPHERE_H
#define SPHERE_H

#include "hittable.h"

class sphere : public hittable
{
public:
    sphere() {}
    ~sphere() {}
    sphere(vecfloat cen, float r) : center(cen), radius(r) {}
    bool hit(const ray &r, float t_min, float t_max, hit_record &rec) const;

protected:
    vecfloat center;
    float radius;
};

#endif

sphere.cc

#include "include/sphere.h"

bool sphere::hit(const ray &r, float t_min, float t_max, hit_record &rec) const
{
    vecfloat oc = r.origin() - center;
    float a = oc.dot_product(r.direction());
    float b = oc.dot_product(oc) - radius * radius;
    float c = oc.dot_product(oc) - radius * radius;
    float discriminant = b * b - a * c;
    if (discriminant > 0)
    {
        float temp = (-b - sqrt(b * b - a * c)) / a;
        if (temp < t_max && temp > t_min)
        {
            rec.t = temp;
            rec.p = r.point_at_parameter(rec.t);
            rec.normal = (rec.p - center) / radius;
            return true;
        }
        temp = (-b + sqrt(b * b - a * c)) / a;
        if (temp < t_max && temp > t_min)
        {
            rec.t = temp;
            rec.p = r.point_at_parameter(rec.t);
            rec.normal = (rec.p - center) / radius;
            return true;
        }
    }
    return false;
}

hittable.h

#ifndef HITTABLELIST_H
#define HITTABLELIST_H
#include "hittable.h"

class hittable_list : public hittable
{
public:
    hittable_list() {}

    hittable_list(hittable **l, int n)
    {
        list = l;
        list_size = n;
    }
    bool hit(const ray &r, float t_min, float t_max, hit_record &rec) const;
    ~hittable_list() {}

protected:
    hittable **list;
    int list_size;
};

#endif

hittable.cc

#include "include/hittablelist.h"

bool hittable_list::hit(const ray &r, float t_min, float t_max, hit_record &rec) const
{

    hit_record temp_rec;
    auto hit_anything = false;
    auto closet_so_far = t_max;
    for (int i = 0; i < list_size; i++)
    {
        if (list[i]->hit(r, t_min, closet_so_far, temp_rec))
        {
            hit_anything = true;
            closet_so_far = temp_rec.t;
            rec = temp_rec;
        }
    }
    return hit_anything;
}

【问题讨论】:

  • 我从来没有想过要制作一个纯虚拟析构函数。想知道会发生什么,它是相关的。
  • 是的,就是这样。让我把代码缩小到 minimal reproducible example 并写下来。
  • 呵呵。无法重现未定义的vtable
  • 这能回答你的问题吗? Undefined reference to vtable,特别是提到检查链接命令的答案。
  • @JaMiT 会这样做,但主要是偶然的。这里的关键是hittable 必须定义析构函数来解决这段代码的所有问题。它可以保持纯粹的virtual,但它必须被定义。从它派生的类必须有可调用的东西。

标签: c++ inheritance polymorphism abstract-class


【解决方案1】:

解决方案

改变

virtual ~hittable() = 0; 

进入

virtual ~hittable() = default; 

virtual ~hittable()
{
    // does nothing
} 

析构函数可以保持纯虚,但它必须有一个定义。

hittable::~hittable()
{
    // does nothing
}

那么发生了什么? 我们可以将给定的代码分解成下面的例子(注意我不能用这个代码或给定的代码重现丢失的vtable,但无论如何,上面都会修复它)

小例子:

class hittable
{
public:
    virtual ~hittable() = 0; // here we have a destructor, 
                             // but there's no implementation 
                             // so there is nothing for the
                             // destructors of derived classes 
                             // to call  

    virtual bool hit() const = 0;
};

class sphere: public hittable
{
public:
    bool hit() const;

};

bool sphere::hit() const
{
    return false;
}

析构函数调用任意基类析构函数,当shpere去调用~hittable时,发现虽然声明了~hittable,但没有实现。没什么可打电话的。

【讨论】:

  • 由于某种原因,这仍然给我同样的错误。
  • 发生了其他事情。我们可以得到minimal reproducible example 吗?
  • 好的,当文件在头部而不是单独的cc文件时它可以工作。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-08-14
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多