Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Modern C and C++: it is possible to use one defined structure for other declared structure?

Let's say I want to make some sort of engine which should support loading graphical Images, so I have

 struct Image;
 Image* load_image_from_file(...);

I don't want external world to know what Image really is, they'll deal only with pointers to it.

However inside engine I want to use specific type, e.g. SDL_Surface which is fully defined in SDL.

Can I somehow redifine Image for this file so compiler assumes SDL_Surface* each time it sees Image* (other than macro)?

I.e. I want something like typedef struct SDL_Surface Image;

All attempts like

 using Image = SDL_Surface;
 typedef SDL_Surface Image;
 typedef struct SDL_Surface Image;

produce compile time error (http://codepad.org/1cFn18oh).

I know that I can use something like struct Image{SDL_Surface* surface}; in engine.c/engine.cpp but it creates unnecessary indirection and I'll have to type ->surface. Another dirty solution is to use explicit casts, e.g.((SDL_Surface*)image) but I'm interesting in cleaner renaming.

PS. I'm interested in answers for both C and C++.

like image 228
user2998754 Avatar asked May 10 '15 14:05

user2998754


2 Answers

Simply define an alias:

using Image = SDL_Surface;
typedef SDL_Surface Image;

which compiles just fine.

If you need to hide SDL_Surface, just import it into some anonymous or detail-named namespace and use it like this.


If, for some reasons, you want to define your own Image type, you can always declare a(n) (implicit) conversion function/operator, like:

struct Image {
    /* explicit */ operator SDL_Surface() const;
    // ...
};

and also back to Image, if you need that:

struct Image {
    /* explicit */ Image(SDL_Surface&&);
    /* explicit */ Image(SDL_Surface const&);
    // ...
};
like image 128
Shoe Avatar answered Sep 28 '22 02:09

Shoe


In C++ you can use the inheritance:

// User view
struct Image;                  // forward declaration (inclomplete type).  
Image* LoadFromFile (...);     // You can use pointer to incomplete type

// Implementation view
struct Image: SDL_Surface { }; // here you go !! :-)

Remark: it would be safer to use classes and private inheritance, so that only Image knows that it is an SDL_Surface.

In some cases it could be undesirable to to inherit from an existing implementation class (for example if you'd need a virtual destructor and the base class doesn't). Then the PIMPL idiom could be an alternative (at the cost of an additional indirection):

//User View unchanged
struct Image;
int TestImage(Image*z); 

//implementation view    
struct Image {
    struct ImageImpl { int x; };  // nested definition or typedef or whatever
    ImageImpl *p;    // works in every case, at cost of an extra indirection instead of a pointer
};
int TestImage(Image* z)
{
return z->p->x;
}

The main advantage of PIMPL here, is that you could expose more than just an incomplete type, and hence offer to the clients some useful member functions. But if you don't need this, and as you already work with poitners to the object on the client side, you could as well go directly to composition and have an ImageImpl member instead of a PIMPL pointer.

In C, you can't use inheritance. But composition would certainly do the trick:

struct Image {
   SDL_Surface s; 
   }; 
like image 20
Christophe Avatar answered Sep 28 '22 01:09

Christophe