我有一个项目,我用点画一个三角形,叫做Sierpinski垫圈。为了达到这个目的,我使用了一个包含x和y值的类Vx。问题是,如果任何方法都是虚拟的,那么它会抛出不同的值,我想知道为什么。虚拟函数如何影响在以下OpenGL代码中生成点的方式?
我的向量类有以下声明:
class Vx {
public:
float x;
float y;
Vx();
Vx(const float& value);
Vx(const float& x, const float& y);
Vx(const Vx& v);
float getX() const;
void setX(const float& x);
float getY() const;
void setY(const float& y);
const float operator [] (int i) const;
operator const float* () const;
operator float* ();
float& operator [] (int i);
};
std::ostream& operator<<(std::ostream& os, const Vx v);
Vx operator+(const Vx& p1, const Vx& p2);
Vx operator/(const Vx& p1, const Vx& p2);它的实施是:
Vectors::Vx::Vx() : x(0), y(0)
{
}
Vectors::Vx::Vx(const float& value) : x(value), y(value)
{
}
Vectors::Vx::Vx(const float& x, const float& y) : x(x), y(y)
{
}
Vectors::Vx::Vx(const Vx& v) : x(v.x), y(v.y)
{
}
float Vectors::Vx::getX() const
{
return this->x;
}
void Vectors::Vx::setX(const float& x)
{
this->x = x;
}
float Vectors::Vx::getY() const
{
return this->y;
}
void Vectors::Vx::setY(const float& y)
{
this->y = y;
}
float& Vectors::Vx::operator[](int i)
{
return *(&x + i);
}
const float Vectors::Vx::operator[](int i) const
{
return *(&x + i);
}
Vectors::Vx::operator const float* () const
{
return static_cast<const float*>(&x);
}
Vectors::Vx::operator float* ()
{
return static_cast<float*>(&x);
}
std::ostream& Vectors::operator<<(std::ostream& os, const Vx v)
{
os << "Vx: " << "x = " << v.x << ", y = " << v.y << std::endl;
return os;
}
Vx Vectors::operator+(const Vx& p1, const Vx& p2)
{
return Vx(p1.x + p2.x, p1.y + p2.y);
}
Vx Vectors::operator/(const Vx& p1, const Vx& p2)
{
return Vx(p1.x / p2.x, p1.y / p2.y);
}我的主类开始设置OpenGL以准备绘制,并在某个时候使用数据创建一个缓冲区,如下所示:
void sierpinskiGasket() {
using namespace Vectors;
/*
Creamos la informacion para el triangulo
*/
const int numPoints = 5000;
Vx points[numPoints];
points[0] = Vx(0.0f, 0.0f);
Vx vertices[] = {
Vx(-0.50f, -0.50f),
Vx(0.50f, -0.50f),
Vx(0.0f, 0.50f)
};
for (int i = 1; i < numPoints;i++) {
int j = rand() % 3;
points[i] = (points[i - 1] + vertices[j]) / 2;
}
/*
Generamos el buffer para el triangulo
*/
unsigned int triangle_vbo;
glGenBuffers(1, &triangle_vbo);
glBindBuffer(GL_ARRAY_BUFFER, triangle_vbo);
glBufferData(GL_ARRAY_BUFFER, sizeof(points), points, GL_STATIC_DRAW);
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, (void*)0);
}我得到的结果是下一个三角形(没关系):

但是,如果我将Vx类的任何方法更改为虚拟,则会发生以下情况:

发布于 2020-12-05 10:43:31
经过一些研究后,我找到了这个问题的更详细的答案,因为它解释了为什么虚拟函数会影响类成员拥有不同内存分配方式的原因,此外,还有c++引用中的一些文档,这些文档也解释了多态对象和内存分配。
事实上,这是不明确的行为,以下问题的答案解释了为什么在一个简短和更好的方式。
https://stackoverflow.com/a/48300540/13716517
此外,我还想在接下来的两个链接中添加c++引用的内容:
https://en.cppreference.com/w/cpp/language/object
https://en.cppreference.com/w/cpp/language/memory_model
在这里,我们可以从以下网站找到下一个文档:
多态对象:声明或继承至少一个虚拟函数的类类型的对象是多态对象。在每个多态对象中,实现存储附加信息(在每个现有实现中,它是一个指针,除非优化输出),虚拟函数调用和RTTI特性(dynamic_cast和typeid)使用这些信息来确定在运行时创建对象的类型,而不管在其中使用的表达式如何。对于非多态对象,值的解释由使用对象的表达式确定,并在编译时确定。内存位置:内存位置是标量类型的对象(算术类型、指针类型、枚举类型或std::nullptr_t)或最大的非零长度位字段连续序列。注意:语言的各种特性,例如引用和虚拟函数,可能涉及程序无法访问但由实现管理的其他内存位置。
考虑到所有这些,我们可以更详细地看到使用虚拟函数的未定义行为来自何处,了解它们在生成点时是如何改变行为的。
发布于 2020-12-05 05:44:38
具有虚拟方法的类具有指向VMT (虚拟方法表)的隐式字段指针。您可以通过打印带有和不带虚拟方法的sizeof(Vx)来检查它。类和结构的内部表示不是由C++标准指定的,而且在编译器之间也各不相同,因此您不应该将带有虚拟方法的类传递给像glBufferData这样的函数。
https://stackoverflow.com/questions/65148082
复制相似问题