James
James

Reputation: 2058

Extending an existing class like a namespace (C++)?

I'm writing in second-person just because its easy, for you.

You are working with a game engine and really wish a particular engine class had a new method that does 'bla'. But you'd rather not spread your 'game' code into the 'engine' code.

So you could derive a new class from it with your one new method and put that code in your 'game' source directory, but maybe there's another option?

So this is probably completely illegal in the C++ language, but you thought at first, "perhaps I can add a new method to an existing class via my own header that includes the 'parent' header and some special syntax. This is possible when working with a namespace, for example..."

Assuming you can't declare methods of a class across multiple headers (and you are pretty darn sure you can't), what are the other options that support a clean divide between 'middleware/engine/library' and 'application', you wonder?

Upvotes: 5

Views: 5565

Answers (8)

Steve Jessop
Steve Jessop

Reputation: 279295

If the new method will be implemented using the existing public interface, then arguably it's more object oriented for it to be a separate function rather than a method. At least, Scott Meyers argues that it is.

Why? Because it gives better encapsulation. IIRC the argument goes that the class interface should define things that the object does. Helper-style functions are things that can be done with/to the object, not things that the object must do itself. So they don't belong in the class. If they are in the class, they can unnecessarily access private members and hence widen the hiding of that member and hence the number of lines of code that need to be touched if the private member changes in any way.

Of course if you want to access protected members then you must inherit. If your desired method requires per-instance state, but not access to protected members, then you can either inherit or composite according to taste - the former is usually more concise, but has certain disadvantages if the relationship isn't really "is a".

Upvotes: 1

Tom Barta
Tom Barta

Reputation: 1284

My only question to you is, "does your added functionality need to be a member function, or can it be a free function?" If what you want to do can be solved using the class's existing interface, then the only difference is the syntax, and you should use a free function (if you think that's "ugly", then... suck it up and move on, C++ wasn't designed for monkeypatching).

If you're trying to get at the internal guts of the class, it may be a sign that the original class is lacking in flexibility (it doesn't expose enough information for you to do what you want from the public interface). If that's the case, maybe the original class can be "completed", and you're back to putting a free function on top of it.

If absolutely none of that will work, and you just must have a member function (e.g. original class provided protected members you want to get at, and you don't have the freedom to modify the original interface)... only then resort to inheritance and member-function implementation.

For an in-depth discussion (and deconstruction of std::string'), check out this Guru of the Week "Monolith" class article.

Upvotes: 8

Paul Nathan
Paul Nathan

Reputation: 40319

Sounds like a classic inheritance problem to me. Except I would drop the code in an "Engine Enhancements" directory & include that concept in your architecture.

Upvotes: 0

Menkboy
Menkboy

Reputation: 1635

  • Inheritance (as you pointed out), or
  • Use a function instead of a method, or
  • Alter the engine code itself, but isolate and manage the changes using a patch-manager like quilt or Mercurial/MQ

I don't see what's wrong with inheritance in this context though.

Upvotes: 1

Don Wakefield
Don Wakefield

Reputation: 8832

Or Categories in Objective C.

There are conceptual approaches to extending class architectures (not single classes) in C++, but it's not a casual act, and requires planning ahead of time. Sorry.

Upvotes: 0

Moishe Lettvin
Moishe Lettvin

Reputation: 8471

You could do something COM-like, where the base class supports a QueryInterface() method which lets you ask for an interface that has that method on it. This is fairly trivial to implement in C++, you don't need COM per se.

You could also "pretend" to be a more dynamic language and have an array of callbacks as "methods" and gin up a way to call them using templates or macros and pushing 'this' onto the stack before the rest of the parameters. But it would be insane :)

Upvotes: 0

Jonathan Adelson
Jonathan Adelson

Reputation: 3321

Sounds like you want Ruby mixins. Not sure there's anything close in C++. I think you have to do the inheritance.

Edit: You might be able to put a friend method in and use it like a mixin, but I think you'd start to break your encapsulation in a bad way.

Upvotes: 0

Redbeard
Redbeard

Reputation: 1018

Sounds like a 'acts upon' relationship, which would not fit in an inheritance (use sparingly!).

One option would be a composition utility class that acts upon a certain instance of the 'Engine' by being instantiated with a pointer to it.

Upvotes: 1

Related Questions