C++ classes, inheritance and portability

Discussions on more advanced topics such as monolithic vs micro-kernels, transactional memory models, and paging vs segmentation should go here. Use this forum to expand and improve the wiki!
FlashBurn
Member
Member
Posts: 313
Joined: Fri Oct 20, 2006 10:14 am

Re: C++ classes, inheritance and portability

Post by FlashBurn »

XenOS wrote: but the question is, if one uses C style coding anyway, why not use C from the beginning instead of C++?
And this says if you want to code in C++ you always have to use oo-style or go back to C! I use oo where it is better and easier and use C-style where it is faster and easier.
User avatar
xenos
Member
Member
Posts: 1118
Joined: Thu Aug 11, 2005 11:00 pm
Libera.chat IRC: xenos1984
Location: Tartu, Estonia
Contact:

Re: C++ classes, inheritance and portability

Post by xenos »

That's exactly the reason why I prefer using C++ in my kernel and device drivers. IMHO, C++ classes and objects provide a very good abstraction of devices such as serial / parallel / USB ports, drives, CPUs, and processing objects such as processes, threads, messages...
Programmers' Hardware Database // GitHub user: xenos1984; OS project: NOS
rdos
Member
Member
Posts: 3276
Joined: Wed Oct 01, 2008 1:55 pm

Re: C++ classes, inheritance and portability

Post by rdos »

One can create horrible, non-OO oriented code in C++, and OO code in assembly. It is not the language used that defines if code is object oriented or not, it is how the code is designed and implemented. I use an OO approach in my (currently) assembly-only kernel, and one day I will provide a real C++ interface to system components in the kernel, and write some more complex drivers in C++.

One thing that doesn't map well to C++ is the (prefered) use of handles instead of pointers in typical OS interfaces. Handles provides a much stronger validation of objects than using only pointers. When it comes to userlevel interfaces, the direct use of pointers is very bad.
rdos
Member
Member
Posts: 3276
Joined: Wed Oct 01, 2008 1:55 pm

Re: C++ classes, inheritance and portability

Post by rdos »

berkus wrote:We heard that from Linus already. C++ provides excellent support for handles, sometimes you don't even know it's a handle and just think it's a pointer. Think about it.
Can you give an example about this "excellent support for handles", and how it can validate handles without any external support? I don't count various aliasing of addresses into handles, as this is not safe. Seriously, I'm interested in how to solve this issue myself.
User avatar
xenos
Member
Member
Posts: 1118
Joined: Thu Aug 11, 2005 11:00 pm
Libera.chat IRC: xenos1984
Location: Tartu, Estonia
Contact:

Re: C++ classes, inheritance and portability

Post by xenos »

Of course one can also use OO in assembly code and non-OO in C++. But in my opinion it is much simpler in C++ as it provides classes, templates, inheritance and so on, which make it much easier to implement an OO design. Of course, if you use an assembler which supports such basic OO elements (or at least supports macros such that one can write an own implementation of such elements), implementing an OO design in assembler is just as easy as in C++.
Programmers' Hardware Database // GitHub user: xenos1984; OS project: NOS
User avatar
Solar
Member
Member
Posts: 7615
Joined: Thu Nov 16, 2006 12:01 pm
Location: Germany
Contact:

Re: C++ classes, inheritance and portability

Post by Solar »

XenOS wrote:...the object oriented nature of C++...
Chiming in on this:

C++ is, by design, a multi-paradigm language. Reducing it to its OO subset is not doing the language justice (and not effective, either).

The book "The C++ Programming Language" by Stroustrup begins with a quote by Benjamin Lee Whorf: "Language shapes the way we think, and determines what we can think about". This is not by accident, as this quote is very fitting with regards to C++. Don't get caught in some "paradigm" strait jacket.
Every good solution is obvious once you've found it.
rdos
Member
Member
Posts: 3276
Joined: Wed Oct 01, 2008 1:55 pm

Re: C++ classes, inheritance and portability

Post by rdos »

Uhm, I never work with written specifications when I write OS-code. I keep all the details in my head. :mrgreen:

But, I can give you some basics.

I already have som handle-functions that looks like this in C:

Code: Select all


// base type for handles

struct THandleBase
{
    int type_id;
    int handle;
};

// register handle, and auto-deletion when a process terminates

void RegisterHandle(int type_id, void (*delete(THandleBase *ptr)));

// basic functions

THandleBase *AllocateHandle(int size, int type_id);
void FreeHandle(THandleBase *ptr);
THandleBase *DerefHandle(int handle);

These should somehow be encapsulated into C++ classes.
User avatar
xenos
Member
Member
Posts: 1118
Joined: Thu Aug 11, 2005 11:00 pm
Libera.chat IRC: xenos1984
Location: Tartu, Estonia
Contact:

Re: C++ classes, inheritance and portability

Post by xenos »

Solar wrote:C++ is, by design, a multi-paradigm language. Reducing it to its OO subset is not doing the language justice (and not effective, either).
Of course, C++ has many other nice features besides OO, things like template functions, overloading, namespaces and so on, and one can do very nice things in C++ without even touching OO.

I just wanted to mention that if one doesn't use any of these features, or uses them only to mimic the behavior of C, one might get along easier using C from the beginning.
Programmers' Hardware Database // GitHub user: xenos1984; OS project: NOS
User avatar
Solar
Member
Member
Posts: 7615
Joined: Thu Nov 16, 2006 12:01 pm
Location: Germany
Contact:

Re: C++ classes, inheritance and portability

Post by Solar »

I was aiming at the original comment that XenOS didn't want to use that "namespace approach" because to him "it mainly circumvents the object oriented nature of C++".

I wanted to point out that C++ is, first and foremost, a pragmatic language. Use whatever floats your boat. Don't worry about whether it's "properly OO" or not. "Clean design", in C++, means "readable" and "maintainable", not "pure".

(It's something I came to respect, and to a certain extend, love, in C++ and Perl. I cringe every time I have to write up a Java class only to put a 'static void main' in there. Of course, it has been abused as a lame excuse for shoddy design, giving both languages a bad rep...)
Every good solution is obvious once you've found it.
User avatar
xenos
Member
Member
Posts: 1118
Joined: Thu Aug 11, 2005 11:00 pm
Libera.chat IRC: xenos1984
Location: Tartu, Estonia
Contact:

Re: C++ classes, inheritance and portability

Post by xenos »

@berkus: Of course one can write plain C code in C++, that's just what I said, and it's not breaking any C++ rules. But that can also be done in C, without dealing with things like name mangling and so on. So it appears to me that writing plain C code without any of the C++ features (and maybe mixing it with assembly) in C is simpler than doing the same in C++.

@Solar: Thanks for clarification. The reason why I tried to stick to the OO paradigm is not that I'm using C++, but it's rather the other way round: I use C++ in my kernel because my aim is to implement an OO design. Some parts of my kernel, such as the task scheduler or the memory manager, encapsulate certain functionalities and operate on a set of private data, so my first idea was to model them as instances of C++ classes. But after some time of thinking and writing simple examples for the different designs it seems that using namespaces for such "one-instance-only objects" (I don't want to use the word singleton here) fits my needs better than the other approaches. I guess I will use C++ classes / objects only if I actually need more than one instance of something, such as address spaces, I/O APICs, CPUs, buses or whatever.
Programmers' Hardware Database // GitHub user: xenos1984; OS project: NOS
rdos
Member
Member
Posts: 3276
Joined: Wed Oct 01, 2008 1:55 pm

Re: C++ classes, inheritance and portability

Post by rdos »

OK, I should have outlined how the handle basics works. The handle numbers are per process, and uses a single number series for all devices that use handles. In the current implementation they are 16-bits. There is no relationship between a handle number and the object it encapsulates. The handle module has an array that links handle numbers to a memory pointer and a memory pool.

A handle using module will first identify it's ID, and a delete function to close open handles when a process terminates without closing all of its handles. This should be a static method (probably).

Next, it will allocate handles.

Code: Select all

THandleBase *AllocateHandle(int size, int type_id);
void FreeHandle(THandleBase *ptr);
Allocate handle takes a size for the object to be encapsulated, and the previously defined ID (which the class should keep as an global). It then gets a pointer to a memory block that first contains the mandatory fields (ID and handle number), and some space for itself (as indicated by size). Usually, drivers
will put a selector / memory address here. In this case it could be a pointer to the current object to be encapsulated (this pointer). IOW, the size parameter
will always be 12, and the returned type will look something like this:

Code: Select all

struct THandle
{
    int type_id;
    int handle;
    void *object;
};
I think that allocate handle should be in the constructor and free handle should be in the desctructor of the basic handle-class. This class will also
contain something that will dereferences handles:

Code: Select all


class THandleObject
{
protected:
    THandleObject(int ID);
    ~THandleObject();

   static THandleObject *Deref(int Handle, int ID);  

    int Handle;

public:
    int GetHandle() {return Handle};
};

THandleObject::THandleObject(int ID)
{
    THandle *handleobj = AllocateHandle(sizeof(THandle), ID);
    Handle = handleobj->handle;
    handleobj->object = this;
}

THandleObject::~THandleObject();
{
    THandle *handleobj = DerefHandle(handle);
    FreeHandle(handleobj);
}

THandleObject *THandleObject::Deref(int Handle)
{
    THandle *handleobj = DerefHandle(handle);
    if (handleobj)
        return handleobj->object;
    else
        return 0;
}

classs TSomeHandleObject : public THandleObject
{
    TSomeHandleObject();

   static void DoSomeFunction(int Handle, void *Buf);

}

TSomeHandleObject::TSomeHandleObject()
  : THandleObject(ID)
{
}

TSomeHandleObject::DoSomeFunction(int Handle, void *Buf)
{
    TSomeHandleObject *obj = (TSomeHandleObject *)Deref(Handle, ID);

// do something
    
}
The problem I can see here is that all methods end up as static, which seems to defeat the idea of OO.
User avatar
xenos
Member
Member
Posts: 1118
Joined: Thu Aug 11, 2005 11:00 pm
Libera.chat IRC: xenos1984
Location: Tartu, Estonia
Contact:

Re: C++ classes, inheritance and portability

Post by xenos »

berkus wrote:It really isn't. C++ is more strict about declarations and preserves a lot more type information, so it's a lot harder to shoot yourself in the foot than with plain C.
Yes, that's IMHO one of the "features" of C++. If you make use of C++'s stricter typing, you already left the "pure C" world and stepped right into the world of C++ programming.
Programmers' Hardware Database // GitHub user: xenos1984; OS project: NOS
Post Reply