1

I am writing a small program for learning C++ and 3D.

I have already written a vertex class with usefull methods. (like Dot,Cross, etc...)

class cVector {
    ...
    float x, y, z;
    ...
    float dot(cVector& v);      
    cVector cross(cVector& v);
    ...
}

Now I realize OpenGL expects buffers where elements are more like a struct (VBO).

struct sVector {
    float x, y, z;
}

So my vertex class is no longer useless, because if i want to manipulate data in the buffer :
1 - I need to extract data of elements in the buffer.
2 - Create a temporary instance of vertex class with the data.
3 - Use vertex class method. (Dot, cross, etc...)
4 - Put the data back to the buffer.
It's not very efficient :(.

I wonder if I should not use a struct to organize my vectors and create global functions that take a pointer to a struct as an argument. I could handle data buffers more efficiently (just moving pointer) but I feel i would lose the "convenient power" of C++.

In every 3D C++ source code i ever see, all use class for vertex but i dont understand how they can manipulate large amount of vertex in a "struct like" buffer.

Can you help me to understand ? What is the best approach ?

Danvil
  • 22,240
  • 19
  • 65
  • 88
rom1nux
  • 110
  • 1
  • 11
  • possible duplicate of [What are the differences between struct and class in C++?](http://stackoverflow.com/questions/92859/what-are-the-differences-between-struct-and-class-in-c) – juanchopanza Apr 12 '14 at 14:30
  • 1
    As you can see it's for specific problem, not generalized paradigm... – rom1nux Apr 12 '14 at 14:32
  • still, there's no difference, so you're asking the wrong question. – juanchopanza Apr 12 '14 at 14:32
  • @OP, you may use the one with a constructor and destructor just fine. However, instead of using `float X, Y, Z`.. I'd advise you to use an array. This way when passing it to OpenGL, you can pass just the array and not the whole class. If the only members of the class is X, Y and Z with the manipulation functions, then it is the same size as the struct that has no manipulation functions.. What really determines the size of a class is its variable members, not its functions afaik.. Just the member array, it'll save you trouble if anything. – Brandon Apr 12 '14 at 14:36
  • @CantChooseUsernames: that is almost true, but do not forget the vtable and the corresponding pointers when you inherit. – László Papp Apr 12 '14 at 14:41
  • Sorry if it's a duplicate question, it's hard for me to explain my problem. I re-read more than once the linked question but i think a miss something probably because of my bad english language. In other word, if i got a pointer to the cVector class (like cVector *ptr) i can do safely something like memset(ptr,0x0,sizeof(float)*3); or memcpy(ptr,&myarray[9],sizeof(float)*3); like i do with sVector struct ? An other example, can i do ptr=(cVector *)&myarray[9]; and ptr->x=2; ptr->dot(...); etc... ? (myarray[] is an array of float). – rom1nux Apr 12 '14 at 15:19
  • @CantChooseUsernames: There is no reason you cannot do both if you use an anonymous union, in fact this is ***very*** common. – Andon M. Coleman Apr 12 '14 at 16:50

2 Answers2

2

The most common approach in a language like C++ is actually neither of these things.

You are more likely to encounter the following:

struct Vector3 {
  union {
    struct {
      float x,y,z;
    };
    float v [3];
  };

  ...

  Vector3 (float x_, float y_, float z_) : x (x_), y (y_), z (z_) { };

  float Norm      (void) { return sqrt ((x * x) + (y * y) + (z * z)); }
  void  Normalize (void) {
    float norm = Norm ();
    
    v [0] /= norm;
    v [1] /= norm;
    v [2] /= norm;
  }
};

The reason for this is because using anonymous unions and structs, you can treat the data as either an array of floats (v [...]) or reference the individual components by their name (x, y, z) without a lot of muss or fuss. You get the best of both worlds by using the language more intelligently.

As for the difference between a struct and a class in this particular case, there is none from the perspective of memory representation. The only real difference between a class and a struct in C++ is the default access; struct has public access by default.

When GL needs to access the object's internal memory, you would accomplish this by passing it the pointer: Vector3::v or the individual components, depending on the particular function.

For instance:

Vector3 vec   (1.0f, 2.0f, 3.0f);
---------------------------------

glVertex3fv   (vec.v);

    and

glVertex3f    (vec.x, vec.y, vec.z);

    are equivalent

On a side-note, anonymous structures are a non-standard extension to C++ but supported virtually everywhere. In the case that you have a compiler that does not support them, you may have to qualify access to x, y, and z by giving the struct a name.

struct Vector3 {
  union {
    struct {
      float x,y,z;
    } s;
    float v [3];
  };
};

If you write your struct this way, then:

Vector3 vec;
assert (vec.v [0] == vec.s.x);

It is messier to have to qualify x that way (using an anonymous struct you can use vec.x).

Community
  • 1
  • 1
Andon M. Coleman
  • 42,359
  • 2
  • 81
  • 106
  • I understand this but OP is asking if they can pass a class with a bunch of constructors, accessors and mutators to a C function that accepts a void pointer. https://ideone.com/F2KPdF – Brandon Apr 12 '14 at 17:08
  • @CantChooseUsernames: You don't pass classes, you pass objects (instances of classes). Since the only time constructors, accessors, mutators, etc. really have anything to do with a particular instantiated object is with polymorphism this doesn't matter in this case. The instantiated object is not going to have extra memory lying around to facilitate each of those functions (e.g. `vtable`). You could pass the address to an instance of this object to GL if you wanted, but I would highly suggest passing `Vector3::v` instead particularly if inheritance, etc. is ever involved. – Andon M. Coleman Apr 12 '14 at 17:12
  • Oh man. You're just repeating what I said in a previous comment on the original post.. It was already pointed out by @LaszloPapp; that vtables and inheritance affect it.. My suggestion to OP was also to use an internal array and pass it the array directly.. You are correct about the union though. I didn't think about that. – Brandon Apr 12 '14 at 17:15
  • @CantChooseUsernames: Not at all, you advocated structuring the internal data store of the object into an array which prevents accessing components by name without writing selectors / mutators. The whole point of this answer was to demonstrate that by using a union, you don't need that. – Andon M. Coleman Apr 12 '14 at 17:17
  • When did I say that OP MUST use an accessor to access the array? Who said it can't be public just like your union members or the float members of the struct? I specifically said OP just wanted to know whether or not they can pass to a C function, a class with a constructor and some accessors or mutators. Yes your structure with a union is nice, but add some functions to show them it is acceptable (which is what they are really asking). I'd gladly remove my answer then.. I will +1 you for the union and good explanation though. It is nice. – Brandon Apr 12 '14 at 17:18
  • You did not say that they must do that, it is implied though. If the only thing the class stores is an array, then there is no way to access Z by its name without writing a function like `float getZ (void) { return v [2]; }`. It is not a big deal for a 3D vector class like this, but when you write matrix classes then writing 16 different functions to access the components of a 4x4 matrix by name rather than index (e.g. `m44 ()` returns column 4, row 4) is extremely cumbersome. – Andon M. Coleman Apr 12 '14 at 17:35
  • How exactly is it implied? My answer states/stated: `pass it CVector::the_array`. Where exactly is the a `function call` there? I've also mentioned passing the array in my comments. I did not say "make a function to access the array". You assume that I do not know anything about OpenGL, C++, Math or English. That's the problem here. At least that's what I get from your replies. – Brandon Apr 12 '14 at 18:01
  • @CantChooseUsernames: This was all in response to your original comment: *"However, instead of using float X, Y, Z.. I'd advise you to use an array."* You had not even written an answer when this discussion began. – Andon M. Coleman Apr 12 '14 at 18:04
  • Fair enough then.. I guess. I'll just have to be more careful about saying things now due to everything "implying" something else. – Brandon Apr 12 '14 at 18:05
  • 1
    By the way, I am sorry if it seemed like I was assuming a lack of understanding on your part in any of the things you mentioned. I try to write my answers and comments in a way that someone who stumbles across this from Google can benefit from, so that sometimes involves stating things that you might reasonably assume *current* participants in a discussion already understand. I meant no offense. – Andon M. Coleman Apr 12 '14 at 18:17
  • Thank you very much all for your clear explanations and tricks, this take time to come up in my brain but now i think i understand. I'm going to test. – rom1nux Apr 17 '14 at 14:46
0

There is exactly one difference between struct and class: For class the default scope is private, while for struct it is public.

So

class cVector {
    ...
    float x, y, z; // data
    ...
    float dot(cVector& v); // just a function
    cVector cross(cVector& v); // just a function
    ...
}

and

struct sVector {
   float x, y, z; // data
}

have exactly the same memory layout (given that x,y,z are the only members variables of cVector).

You can use &v.x to get a pointer to (x,y,z) for OpenGL, e.g. glVertex3f(&v.x);.

You can even do the following to get a pointer to a continuous sequence of vertices for usage with OpenGL:

std::vector<cVector> vertices(100);
const float* data = &(vertices[0].x);
Danvil
  • 22,240
  • 19
  • 65
  • 88