8

I was recently doing some Windows Api coding (still doing it). And I was trying to find the best way to wrap the WNDCLASSEX into a C++ class, when I had this crazy idea, the WNDCLASSEX is a struct right? (even though it is written in c) and in C++ structs are treated as classes, so why don't I declare my WinCLass as a derivative of WNDCLASSEX , so I tried:

 class WinClass : protected WNDCLASSEX

And it worked! Then I tried using it with SDL structs but those worked too. But some structs(especially SDL ones) either don't compile or cause unexplained runtime errors when I derive classes from them. So my question: Is this kind of C struct use recommended? Is it actually used by pros, or is it just a lame hack? Should I use for my wrapppers or apps, or will this just introduce unexplained bugs?

ApprenticeHacker
  • 21,351
  • 27
  • 103
  • 153
  • If you're interested in Win32 wrappers, you might want to look at how [existing libraries](http://en.wikipedia.org/wiki/Windows_API#Wrapper_libraries) are designed. [ATL](http://en.wikipedia.org/wiki/Active_Template_Library) and [WTL](http://wtl.sourceforge.net/) might be of particular interest. Also, the [RSWL](http://www.relisoft.com/rswl.html) looked interesting when it was in its infancy, but I haven't heard much about it lately (like the fact that it was named RSWL :) – Merlyn Morgan-Graham Jul 17 '11 at 05:16
  • 2
    Personally I would use composition rather than inheritance in this situation (i.e. `class WinClass { WNDCLASSEX wcex; };` instead of `class WinClass : protected WNDCLASSEX {};`). It seems more sensible to use composition for this case. – In silico Jul 17 '11 at 05:19

3 Answers3

4

As long as you don't start adding virtual members, it should be fine. If you do add virtual members, the virtual table pointer could screw with your memory layout of the struct.

This includes virtual destructors!

Blindy
  • 65,249
  • 10
  • 91
  • 131
  • 1
    As long as you cast down properly (ie, implicit cast or `static_cast`), virtuals shouldn't be a problem... – bdonlan Jul 17 '11 at 05:07
  • Why virtuals can be problem if `WinClass` is type-casted to `WNDCLASSEX` ? – Ajay Jul 17 '11 at 05:23
  • 1
    @bdonlan, yes, but the win32 api doesn't *know* to cast down. It expects a pointer to the beginning of the structure. – Blindy Jul 17 '11 at 05:23
  • @Ajay, because a pointer to a structure in C++ is *not* the same as a pointer to a structure in C (which is what the win32 api is). A C++ structure can start after the actual pointer because of the vtable pointer baked into the structure. A C++ compiler knows how to extract the right information, but code already compiled in C won't know what to do with it. – Blindy Jul 17 '11 at 05:26
  • So, you mean to say: Having virtual function in derived class would put something in base class, which wasn't originally there. And you mean if I allocate a derived class, object slicing will/won't happen but this extra-padding in base class/struct would be put in?? I don't believe. – Ajay Jul 17 '11 at 05:48
  • @Blindy, this is a problem if you cast to `void *`, yes, but if you just pass the pointer straight to a win32 function, it's implicitly casted (at the caller, in C++) to the raw struct type, which adjusts the pointer to the base class – bdonlan Jul 17 '11 at 12:59
1

The only difference between a class and a structure in C++ is that of Access specifiers.

For classes the access specifier is private by default.
For structures the access specifier is public by default.

This means if you have a class deriving from other class/struct it will be private inheritance by default &
If you have a structure deriving from other class/structure it will be a public inheritance by default.

One problem though is that since for structure default access specifier is public, they may expose members that maybe should not be exposed to deriving classes. The entire encapsulation has a whole new dimension in this sense. Ofcourse, You If you can change the access specifiers inside the structure which you intend to use as Base, then it is possible to avoid the problem, but it may not be possible because that might affect how the structure is being used from other parts of the program.

EDIT:
Through the comments, I have a fair idea now, what errors you are referring to, the errors are not specifically because you are deriving from a structure but because you are misunderstanding the rules of Inheritance & Access specifiers.

Here is a sample program for demonstration:

#include<iostream>

using namespace std;

struct FirstStruct
{
    private:
        int a;
    public:
        int b;
        FirstStruct():a(10),b(20),c(30)
        {
        }
    protected:
        int c;
};

class MyClass:protected FirstStruct
{
    public: 
        int i;
        MyClass():i(40),j(50),k(60)
        {
        }
        void doSomething()
        {
            a = 100; //private in Base is not accessible in Derived
            b = 100; //Accessible
            c = 100; //Accessible  

            i = 100; //Accessible  
            b = 100; //Accessible  
            c = 100; //Accessible  
        }
    private:
        int j;
    protected:
        int k; 
};

int main()
{
    MyClass obj;
    obj.i = 100; //Accessible
    obj.j = 100; //Error Cannot be Accessed, j is private member
    obj.k = 100; //Error Cannot be Accessed, k is protected member
    obj.a = 100; //Error Cannot be Accessed, a is private member in Base Class
    obj.b = 100; //Error Cannot be Accessed; 
                 //b is protected member of MyClass, because of protected Inheritance
    obj.c = 100; //Error Cannot be Accessed; 
                 //same reason as b


    obj.doSomething();

    return 0;
}

You can check running the same here at Ideone.
You will notice even If you change the type of the Base from struct FirstStruct to class FirstStruct here you get the same errors(nothing more nothing less).

Suggest you to have a look at this answer here, to clear your understanding on Inheritance and Access specifier rules.

Community
  • 1
  • 1
Alok Save
  • 202,538
  • 53
  • 430
  • 533
  • `One problem though is that since for structure default access specifier is public` I have a solution for that. If i inherit the struct like with the protected keyword, `: protected Cstruct` all the members become protected. This works only for C structs (i think). Although i don't know why this happens, Do you? – ApprenticeHacker Jul 17 '11 at 06:03
  • @burningprodigy: Can you post a minimalistic sample of the case you are referring to? I am afraid `Not working` does'nt really tell a lot about the scenario. – Alok Save Jul 17 '11 at 06:13
  • do you mean what i said about the SDL structs? – ApprenticeHacker Jul 17 '11 at 06:17
  • @burningprodigy: Why not just make a minimalistic **standalone**(not dependant on any external sdk etc.) sample using a plain mix of structure and classes to demonstrate the problem? – Alok Save Jul 17 '11 at 06:18
  • Example: (Tested) `struct x { int i; }; class d : protected x {};` Now inside main `d myobj; myobj.i = 10; // Will not work , inaccessible because it is protected (try it)` – ApprenticeHacker Jul 17 '11 at 06:48
  • @burningprodigy: Sorry i got caught up in answering another post. This does not work because with `protected inheritance` all the members of the base class/struct become protected members of the deriving class.Protected members cannot be accessed from outside the class, and hence the error. The error is not because you are using structure as base class, It would be the same even if the base was a class. – Alok Save Jul 17 '11 at 07:01
  • @burningprodigy: Updated the answer, hope that clears some of your doubts. – Alok Save Jul 17 '11 at 09:44
  • thanks, finally its all clear. Sorry if my question was a little vague. – ApprenticeHacker Jul 17 '11 at 10:39
0

I don't have much experience with the Win API, but I know that in C++ the only difference between classes and structs is the default visibility. For classes it is private and for structs it is public. In other words, it is OK to a class be a subclass of a struct.

Keep in mind that as it is a good pratice to declare a virtual destructor for any base class, the struct you are subclassing won't have it.

fbafelipe
  • 4,862
  • 2
  • 25
  • 40