Pure Virtuousness
But there are also things the C++ compiler won't do. For example:
ademo demo_obj(5); cout<<demo_obj.a;
You can't do that because a is private. In the C version, you could easily pull out anything you want from the structure. It is all visible all the time. This is poor for encapsulation. Classic BASIC programmers get bogged down with global variables, and C provides local variables. Same idea. C makes all functions and structure members visible to everyone, where C++ scopes them so you only see them in certain contexts.
Here's the key, though. In reality, the code the C++ compiler generates is exactly the same as what a C compiler would generate. In fact, early C++ "compilers" were just front ends to the C compiler. So while your C program can't access demo_obj.a, that usually doesn't mean the generated code would not allow it (for example, in the case of an error). It just means that the compiler won't give you a way to express that access. So, like I said, sometimes the compiler is preventing you from doing things (for your own good). This is in stark contrast to classic Java running bytecode where the JVM may actually enforce things at runtime.
The LCD class library is a good example of this. It uses pure virtual functions for things it doesn't know how to do (like write to your LCD). That makes the class abstract — you can't construct objects of this type because you didn't give the compiler the whole definition. The =0 behind the getInput() and output() tell the compiler that these functions must appear in a derived class unless the derived class is also abstract.
What's the value to this? The base class can make calls to things like output() even though it doesn't know how it works. Presumably, if an object is actually instantiated some code will exist and that's what gets called. The pure modifier prevents you from creating a class that can't do anything.
Embedded C++ compiler support isn't always so great. Usually vendors that specialize in compilers have great offerings since that's their way of making a profit. But open source or vendor-supplied compilers — even when based on GCC — sometimes have quirks and many of those quirks are related to C++.
The Atmel AVR is a great example. There is a very nice GCC port for this processor and I use it quite a bit. But the C++ support is iffy, at best. For example, the compiler doesn't handle pure virtual functions.
Does it matter? Not really. If you stop and think about it, if the lcdui class provided empty output and input functions, what's the worst that could happen? You might accidentally instantiate the class and it won't really do anything. Just like C.
On the other hand, if I am running Linux on an ARM processor, I still want the compiler to help me find my mistake, so I don't want to just not use pure virtual functions. Consider this change to the class definition:
// get an input code virtual INTYPE getInput(void) PURE; // Write to the LCD #ifndef NOSTRING virtual void output(std::string &ostring) PURE; #else virtual void output(const char *ostring) PURE; #endif };
Further up in the header I have:
#ifndef NOSTRING
#include <sstream>
#include <string>
#include <cstdlib>
#else
#include <string.h>
#include <stdlib.h>
#endif
// not all compilers like pure virtual
#ifndef NOPURE
#define PURE =0
#else
#define PURE { }
#endif
Did I forget to mention the AVR runtime doesn't support C++ strings either (or, at least, the version I am using doesn't). By defining NOSTRING and NOPURE in the makefile, it is possible to get a clean compile with the AVR compiler (or tools with similar limitations) and empty function bodies for pure virtual functions. On more sophisticated compilers, I get essentially the same code, but I get better error checking.
I am keeping the lcdui project up to date as I make changes, so if you pull the code off subversion, it might be slightly different. But the idea is the same: Use C++ features where they make sense and slip back to regular C where they don't. Of course, someone always asks: "What about the performance of virtual functions?" Well, what about it? Pure functions really have to be virtual (think about it). Engineering discipline demands we think about how much performance it really takes and not just base it on opinion. That's a future topic, though.

