# C++, ' ** ' and Graphics Engines...

This topic is 4399 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

## Recommended Posts

I know this is a bit cheeky of me, putting this all into one thread, but I need help with a couple of broad subjects. Firstly, having come from a (shakey) C programming background, I'm still not too sure about classes, and was wondering how programs and APIs such as DirectX can use a single class to create what seems to be a billion unrelated objects, along with the methods to handle them all( I've yet to find a use for the constructor\destructor methods...) secondly, I've been looking around, but I can't seem to find out what the ** operator is for(the place its most often seen is in the definition of main() in C and Cpp) Finally, I'm trying to create my own graphics engine. I not expecting much from it, and I've found an interesting article about it on www.flipcode.com and I'm following their advice, but it feels like my header/source is missing some things. here is the listing for my header;
Quote:
Is there anything else that I need to add mathematically, bearing in mind that I'll implement the drawing\rendering through OpenGL? Also, why can't I get the two flipping pluses to show when I'm trying to write 'C plus plus'?

##### Share on other sites
Quote:
 Original post by webwraithsecondly, I've been looking around, but I can't seem to find out what the ** operator is for(the place its most often seen is in the definition of main() in C and Cpp)
As you already know, using a * in a declaration makes the type a pointer. ** is simply a pointer-to-a-pointer; in fact, you could if you wanted to, go crazy and have a pointer-to-a-pointer-to-a-pointer-to-a-pointer-to-a-pointer.

I imagine you've seen it in main as: char** argv
this is equivalent to char* argv[], or char argv[][].

##### Share on other sites
Quote:
 Original post by webwraithI know this is a bit cheeky of me, putting this all into one thread, but I need help with a couple of broad subjects. Firstly, having come from a (shakey) C programming background, I'm still not too sure about classes, and was wondering how programs and APIs such as DirectX can use a single class to create what seems to be a billion unrelated objects, along with the methods to handle them all( I've yet to find a use for the constructor\destructor methods...)

If you're talking about what I think you are, it's rather simple:

struct Manager {public:    ObjectA * CreateObjectA( void ) {        return new ObjectA;    }    void DestroyObjectA( ObjectA * object ) {        delete object;    }    ObjectB * CreateObjectB( void ) {        return new ObjectB;    }    void DestroyObjectB( ObjectB * object ) {        delete object;    }};

Quote:
 secondly, I've been looking around, but I can't seem to find out what the ** operator is for(the place its most often seen is in the definition of main() in C and Cpp)

That's not an operator, that's a pointer to a pointer. It's often used as the second parameter of main (argv) like so:

int main( int argc , char ** argv );

argv is layed out in a specific manner:

It is a pointer to the beginning of an array.
This array is an array of pointers to the beginnings of arrays of characters (strings).

Thus, if we were to use STL containers and objects (presuming it were legal in this context), it's quite similar to:

std::vector< std::string > argv;

The main difference being they use C style arrays:

std::string * argv; or std::string argv[];

And C style strings:

(char *) * argv; or (char *) argv[];

Quote:
 Finally, I'm trying to create my own graphics engine. I not expecting much from it, and I've found an interesting article about it on www.flipcode.comand I'm following their advice, but it feels like my header/source is missing some things.here is the listing for my header;*snip*Is there anything else that I need to add mathematically, bearing in mind that I'll implement the drawing\rendering through OpenGL?

If there is, you'll find out when you run accross it. And then you can add it. See YAGNI.

Quote:
 Also, why can't I get the two flipping pluses to show when I'm trying to write 'C plus plus'?

The forum PMSes like that. I don't know why either.

##### Share on other sites
When it came to the APIs, I was speaking generally, I know when to use the constructor\destructor methods, I've just never needed them before(the fact that I've never managed to program a functional class before, may have something to do with that...).And I tried to implement a class once, but it was basically a mess, as I tend to need someone going through these things with me step-by-step with actual uses for the classes( in particular, my DirectX book is sitting on the shelf, gathering dust until I can find some simpler examples of good classes)

Thanks to the both of you for the 'pointer to a pointer' part, but I've got another question for you about it now;

what's the point? (pun not intended)

why not use a single pointer to whatever data you want to retrieve?

In the meantime, I'll keep an eye out for those elusive math functions... ;)

##### Share on other sites
Quote:
 Original post by webwraithThanks to the both of you for the 'pointer to a pointer' part, but I've got another question for you about it now;what's the point? (pun not intended)why not use a single pointer to whatever data you want to retrieve?

Because argv (which is a list of arguments given to the program) is an array of C-strings (which are char arrays). Remember, arrays are basically pointers. If it was a pointer to a char, it would be more difficult to know where one argument ended and another began.

##### Share on other sites
If the data you want to retrieve is a pointer (say, a pointer to an interface of some sort), then you need a pointer to a pointer to actually retrieve it. (Or, alternately, a reference to a pointer)

Note that when you say CreateVertexBuffer() in DirectX, that will (at least conceptually) create a CVertexBuffer object internally; initialize it as necessary; and then return a pointer to the actual object (through the pointer-to-pointer interface).

When you call Release() on the interface, it will decrement the refcount, and if it reaches 0, call delete on itself, which will call the destructor, which will clean up any data referenced by the object.

##### Share on other sites
Quote:
 #define SQR(name) name*name //Not too sure this'll work...

SQR(x+1) will expand to: x+1*x+1, which equals x+x+1. Definitely not what you wanted.

Quote:
 #define SQR(name) (name)*(name)

But even better would be:

template <class T>inline T sqr(const T& x){   return x*x;}

In case you're unfamiliar with templates...the above code will create a function sqr(x) for any type that has a defined * operator. The performance will be the same as a #define, but it's typesafe.

-Alex

##### Share on other sites
Quote:
 template inline T sqr(const T& x){ return x*x;}

I've never actually used templates, although I've got a tutorial on a simple one, so how does this actually work?

also, how would I use it? My understanding of templates was that you create a class (or whatever) with one before you can use it, meaning I'd still need a different one for each numerical type I intend to use.

##### Share on other sites
Quote:
Original post by webwraith
Quote:
 template inline T sqr(const T& x){ return x*x;}

I've never actually used templates, although I've got a tutorial on a simple one, so how does this actually work?

Basically, the compiler creates an instance of the function sqr for every data type you use it with. If you pass a float value to sqr, the compiler will create an instance of sqr where the unknown type T is replaced with float. Templates are very powerful code generation tools, which save you, the coder, from having to create n different versions of sqr to deal with n different data types.

Quote:
 Original post by webwraithalso, how would I use it? My understanding of templates was that you create a class with one before you can use it, meaning I'd still need a different one for each numerical type I intend to use.

That is true with templatized classes, but not with templatized functions. Take the sqr function above. In your code, you'd call sqr like so:
sqr<double>(1.0);
This explicitly tells the compiler that 1.0 is to be treated as a value of type double. However, you can omit the part in the < > brackets if you are passing a variable to the function; the compiler can determine the type being passed from the type of the variable.

[Edited by - iNsAn1tY on December 31, 2005 9:49:41 AM]

##### Share on other sites
I'd have thought that 1.0 would have been treated as a float?
I take it, you only need to add the <..> when casting as a new/different type?

Thanks for the help, so far. I'm all ears for any other suggestions

##### Share on other sites
Quote:
 Original post by webwraithI'd have thought that 1.0 would have been treated as a float?I take it, you only need to add the <..> when casting as a new type?Thanks for the help, so far. I'm all ears for any other suggestions

1.0 is treated as a double by default (by Visual Studio.NET, at least). 1.0f is treated as a float.

You actually need to add the < > every time you call the function, if you're not sending a value from a variable.

EDIT: Made another change above, something wasn't right.

[Edited by - iNsAn1tY on December 31, 2005 9:10:08 AM]

##### Share on other sites
Just to make sure you're clear on this...

template <class T>inline T sqr(const T& x){ return x*x; } int ix = 1;float fx = 1.0f;double dx = 1.0;sqr(ix); // compiler generates:  inline int sqr_1(const int& x){return x*x;} sqr(fx);// compiler generates: inline float sqr_2(const float& x) {return x*x;}sqr(dx);// compiler generates: inline double sqr_3(const double& x) { return x*x;}

Now here's a question for someone more C++ savvy than me...
Does passing by const reference instead of by value lose performance?
Will the program have to dereference x inside sqr? Is passing by value faster for POD types?

-Alex

##### Share on other sites
I wouldn't know, I'm not even sure what the difference between a reference and a pointer is. when I first heared about them, I thought they were the same thing with different names

##### Share on other sites
Another thing, if you were trying to cast as a different type, would you use <..> or would you add the cast inside the brackets? Or both?

Finally (phew!) would this need to go in the header, the associated source, or my main source?

##### Share on other sites
Quote:
 Original post by webwraithI wouldn't know, I'm not even sure what the difference between a reference and a pointer is. when I first heared about them, I thought they were the same thing with different names

a reference is a pointer without all the fancy sytax for accesses.

eg

void changeToFive( int* variable ){   *variable = 5; // note the dereference operator...}void changeToFive( int& variable ){   variable = 5;}class SomeClass{public:void someMethod();};void someFunction( SomeClass *someObject ){    someObject->someMethod();//more funky syntax to be aware of}void someFunction( SomeClass &someObject ){    someObject.someMethod();//same thing, but clearer}

pointers can do more, pointer math, have NULL pointers, used for dynamilcally getting memory. references are just easy-on-the-eyes limited pointers.

##### Share on other sites
Quote:
 Another thing, if you were trying to cast as a different type, would you use <..> or would you add the cast inside the brackets? Or both?Finally (phew!) would this need to go in the header, the associated source, or my main source?

Let's say you wanted to generate sqr(double) even though you were passing the function an integer.

Calling sqr( (double) ix ) will accomplish this.

-Alex

##### Share on other sites
Thanks, cipherx, and I'd assume the answer to your question is that passing a value would be quicker, though I don't imagine there would be much of a difference.

Don't quote me on that though...

##### Share on other sites
Calling it by
sqr<double>(someint)
is correct. Cypher's will work, but is containes a nasty little c-style cast.

##### Share on other sites
what's wrong with C-style casts?

##### Share on other sites
Passing by const reference to a non-inline function may lose performance, because the piece of data needs to live on the stack (so that a pointer/reference can be generated). If the function is inline (such as most templates) then the compiler has enough information to optimize the passing to actually be by value -- although whether it chooses to do that may vary based on the compiler and specific compiler flags. If you know it's only for ints, floats, doubles and the like, then pass by value.

In the case of a downcast, C-style casts will perform a static_cast<> when the base type is known, but a reinterpret_cast<> when the base type is not known, without telling you about it. static_cast<> will tell you (using an error) if you're trying to do a downcast without knowing the derived type definition.

  class Junk {    public:      int j;      virtual void junkFunc() = 0;  };  class Base {    public:      virtual void someBaseFunction() = 0;  };  class Derived; // forward declared  Base * b;  Derived * d = (Derived *)b; // will not warn you about the reinterpret-cast; will blow up on use  Derived * d = static_cast< Derived * >( b ); // will tell you about the problem  class Derived : public Junk, public Base {    public:  };  Derived * d = (Derived *)b; // will do the right cast  Derived * d = static_cast< Derived * >( b ); // will do the right cast

C-style casts are fine for POD types, but when you're involving types that may have inheritance, you're better off with static_cast<> (which is almost always the behavior you actually want).

##### Share on other sites
Quote:
Original post by cypherx
Quote:
 #define SQR(name) name*name //Not too sure this'll work...

SQR(x+1) will expand to: x+1*x+1, which equals x+x+1. Definitely not what you wanted.

Quote:
 #define SQR(name) (name)*(name)

-Alex

Even better would be:

#define SQR(name) ( (name) * (name) )

in case some other operator of higher precedence might be adjacent
(not overly likely for '*' but often a possibility in other cases.)

#define MAXPACKETLEN (MAXPACKETDATA - MSGHDRLEN - ACKLEN)

Similar goes for multi statement macros that should be surrounded by { }

#define MsgBox( strx ) { MessageBox(NULL, strx, "Damn You Master of Shoddy!!!", MB_ICONERROR | MB_OK); }

#define ASSERTX( cond , msgx ) { if ( ! ( cond )) MsgBox( msgx ); }

##### Share on other sites
Actually, surrounding macros with {} isn't really safe, because it may lead to a dangling statement (and doesn't REQUIRE that you terminate with a semicolon).

Two better ways of defining ASSERT():

// assume we have this function to deal with a failed assertionvoid assert_failed(char const *file, int line, char const *expression);// note -- no trailing semicolon in the define!#define ASSERT(x) if(x);else assert_failed(__FILE__,__LINE__,#x)// again, no trailing semicolon in the define!#define ASSERT(x) do{if(!(x)) assert_failed(__FILE__,__LINE__,#x);}while(0)`

Both of these will force the user to put a semicolon after usage, and neither of them have a problem with deep if/else statements. The definition by AP, however, might have such problems.

I prefer the first version, but that's just personal aesthetics; both are "correct" and should generate the same code. Actually, the second version isn't vulnerable to the comma operator, whereas the first version would be -- lucky we don't use the comma operator that much in everyday code :-)

##### Share on other sites

This topic is 4399 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.