Reducing internal functionality in a derived function without chaniging the base funcion much?

Started by
2 comments, last by IFooBar 12 years, 8 months ago
Hey guys,

How would you go about creating a new class that has all the functions of an old class but just does a few things in a few functions differently? I'm looking for it to be as non-intrusive as possible. For ex: imagine you have an all-purpose memory allocator and you want a new memory allocator that does things faster by ignoring a few checks. This new memory allocator has all the same functionality as the original one, except it doesn't check for NULL pointers at the beginning of each function.

I was thinking something along the lines of:


// Rename class MemoryManager to MemoryManagerBase
class MemoryManagerBase;
class MemoryManager : public MemoryManagerBase
class FastMemoryManager : public MemoryManagerBase {
// do something here to change ABase's behavior
};


An actual example of the solution I'm using follows. It uses the CRTP pattern and template policies to do it. Any ideas on how to improve things, do it less intrusively or just different ways to do it would be great:

[source lang='cpp']
class OriginalImplementation {
public:
static void check(void *p) {
if (!p)
std::cout << "Bad Pointer!" << std::endl;
}
};

class FastImplementation {
public:
static void check(void *p){
// noop (does this actually result in a no op?)
}
};

template <class T, class Policies>
class MemoryManagerBase {
public:
void free( T *p ) {
// This used to be if (!p) cout << blah
// Now we replace with the checking policy
Policies::check(p);
// .
// old code
}
void oldFunction() {}
};

template <class T>
class OriginalMemoryManager : public MemoryManagerBase<T, OriginalImplementation> {};

template <class T>
class FastMemoryManager : public MemoryManagerBase<T, FastImplementation> {
private:
void oldFunction(); // Don't want old function available in fast implementation
};
[/source]
[size=2]aliak.net
Advertisement
You only seem to be shadowing "oldFunction". If I cast an instance of FastMemoryManager to MemoryBase I can still call it. You could change the inheritance to private, but that requires you to delegate all methods you want to be publicly visible to the base (which renders inheritance mainly useless, containment would be a better choice IMO).

*edit*

I would definately throw an exception in case of a nullptr (if your platform supports those) instead of writing to the console.

A smart compiler (such as vs) should be able to infer that FastImplementation::check(void*) doesn't do anything. It should be able to remove the Policy::check from the code. You can verify this by compiling your example and checking the disassemly of free(T*).

On a side note, don't spend too much time in preemptive optimization. I highly doubt that an "if(blub == nullptr)" check is going to cost you.


Hey guys,

How would you go about creating a new class that has all the functions of an old class but just does a few things in a few functions differently? I'm looking for it to be as non-intrusive as possible. For ex: imagine you have an all-purpose memory allocator and you want a new memory allocator that does things faster by ignoring a few checks. This new memory allocator has all the same functionality as the original one, except it doesn't check for NULL pointers at the beginning of each function.

I was thinking something along the lines of:


// Rename class MemoryManager to MemoryManagerBase
class MemoryManagerBase;
class MemoryManager : public MemoryManagerBase
class FastMemoryManager : public MemoryManagerBase {
// do something here to change ABase's behavior
};


An actual example of the solution I'm using follows. It uses the CRTP pattern and template policies to do it. Any ideas on how to improve things, do it less intrusively or just different ways to do it would be great:

[source lang='cpp']
class OriginalImplementation {
public:
static void check(void *p) {
if (!p)
std::cout << "Bad Pointer!" << std::endl;
}
};

class FastImplementation {
public:
static void check(void *p){
// noop (does this actually result in a no op?)
}
};

template <class T, class Policies>
class MemoryManagerBase {
public:
void free( T *p ) {
// This used to be if (!p) cout << blah
// Now we replace with the checking policy
Policies::check(p);
// .
// old code
}
void oldFunction() {}
};

template <class T>
class OriginalMemoryManager : public MemoryManagerBase<T, OriginalImplementation> {};

template <class T>
class FastMemoryManager : public MemoryManagerBase<T, FastImplementation> {
private:
void oldFunction(); // Don't want old function available in fast implementation
};
[/source]

There're several ways.

The best performing solution would be to use a precompiler to switch between different versions of your class.

The pure OO version would be to inheriting directly from your MemoryManager and overwriting certain methods (performance and virtual tables ?).

Using a controller/behavior class to which some calls will be delegated in combination with templates seems to be a good performance, pre-compiler limited solution. So your solution already looks really promising.

You only seem to be shadowing "oldFunction". If I cast an instance of FastMemoryManager to MemoryBase I can still call it. You could change the inheritance to private, but that requires you to delegate all methods you want to be publicly visible to the base (which renders inheritance mainly useless, containment would be a better choice IMO).


Redesigning the entire thing would be the best choice IMO, but, well, the powers that be... sigh

The casting could indeed be problematic. How about it I just change the access level of the functions in MemoryBase and make them protected, then just add a using MemoryBase::oldFunction statement under public access in the OriginalImplementation. That way casting down to MemoryBase from FastImplementation won't work.



I would definately throw an exception in case of a nullptr (if your platform supports those) instead of writing to the console.

A smart compiler (such as vs) should be able to infer that FastImplementation::check(void*) doesn't do anything. It should be able to remove the Policy::check from the code. You can verify this by compiling your example and checking the disassemly of free(T*).

On a side note, don't spend too much time in preemptive optimization. I highly doubt that an "if(blub == nullptr)" check is going to cost you.


True, this was just to make the example simple enough. Not actually writing to the console in the real implementation, and it's not really just an if statement which we are hiding, there's much more to it than that (lots of thread safety checks and locks for example that we can hide away in the fast version - basically giving the clients more trust, less security).

@Ashaman73: Yeah. I'm rooting for a re-design to take into account these "unexpected" requirements so let's see.
[size=2]aliak.net

This topic is closed to new replies.

Advertisement