Categories
Development

Why derive a C++ class from a struct?

This question came up on Twitter yesterday, and got me thinking. Yeah, why would you do that? The only answer that sprang to mind was for compatibility reasons. If you have the luxury of working on a modern codebase you may not do this sort of thing, but if you have a legacy application or are working with a legacy API you may have need to call C functions that take structs and you may want to manipulate those structs in your C++ code, but do it in a C++ way. Make sense?

Here’s what I’m talking about. Take this C struct for example.

typedef struct tagABC
{
	int      a;
	long     b;
	float    c;
} ABC;

Back in the day, when the ABC structure was created, the developer also created a function to operate on this structure, something like this…

float OldSchoolCDoFancyCalculation(ABC* abc)
{
	return ((float)abc->a+(float)abc->b+abc->c);
}

That looks pretty darned straight forward. The OldSchoolCDoFancyCalculation() function takes a pointer to an ABC struct, sums the field values, and returns the result. Not uncommon. Here’s how it could be used.

	// Old school C style.
	ABC abc;
	abc.a = 10;
	abc.b = 99;
	abc.c = 99.99;

	float value = OldSchoolCDoFancyCalculation(&abc);
	printf("Old School C Struct + C Function == %f\n", value);

Moving on

Let’s say your team has decided to embrace C++ but you don’t want to go back and rewrite a bunch of code, and moving forward you’d like to make use of the nice stuff C++ has to offer. Someone may choose to do something like this with your ABC struct. I say may choose because they may do something totally different, this was the only real example I could think of, so it fits for illustration purposes.

class ABCObject :
	public ABC
{
public:
	ABCObject(int aa, long bb, float cc);
	virtual ~ABCObject();

	void DoFancyCalculation();
	void PrintValue();

private:
	float _value;
}; // ABCObject

Take note. ABCObject is derived from the struct ABC. Yes, of course you can do this in C++. When C++ was being defined this was one of those things that had to be addressed for backward compatibility with C. By default all struct members/fields have public access.

This will allow you to mix instances of ABCObject with the old C functions that operate on ABC structs. Here’s how that would look, and it’s perfectly legitimate.

	// New school C++ style, using old school C code, no problem.
	ABCObject abcObj(11, 100, 100.09);
	float value2 = OldSchoolCDoFancyCalculation(&abcObj);
	printf("New School C++ Object + C Function == %f\n", value2);

Notice we’re passing a pointer an instance of an ABCObject. What the? Sure, you can do that. It’s perfectly legal because ABCObject is derived from the ABC struct. The compiler would notice the function takes an argument of ABC* and ABCObject just happens to fit the “is-a” rule, so it can be passed as an ABC* to the function where it can be operated on like a standard ABC struct pointer.

Like I said, someone could do that. You probably wouldn’t, but the point is you could, and some folks will definitely have need to write code that looks similar to this for some very good reason. More often than not most developers would probably choose to wrap an instance of the old ABC struct as a member variable of the class and then just operate on that from within class methods.

By Rob Fahrni

Husband / Father / Developer