r3dux.org

A number-pimping side project from the valleys in *NEW* upside-down flavour.

  • Home
  • ABOUT
  • OLD SITE
  • SEARCH
  • FEEDBACK

Avoiding down-casts in C++

r3dux | January 31, 2012

If you have to down-cast objects from a base class to a derived class then there’s probably a design flaw in the class structure. It might all work but it’s going to be a brittle design.

// C++ FAQS by Cline & Lowom
// FAQ 162 - What is a down-cast?
// Answer: Trouble.
 
#include <iostream>
 
using namespace std;
 
class Asset
{
	public:
		virtual ~Asset() { }
		virtual bool isLiquidatable() const { return false; } // BAD-FORM: Capability query
};
 
class LiquidAsset : public Asset
{
	protected:
		int mValue;
 
	public:
		LiquidAsset(int value = 100) : mValue(value) { }
 
		int getValue() const { return mValue; }
 
		void setValue(int theValue) { mValue = theValue; }
 
		virtual bool isLiquidatable() const { return true; } // BAD-FORM: Capability query
};
 
// Userland function to liquidate an asset (if it can)
int tryToLiquidate(Asset &asset)
{
	int value;
 
	if ( asset.isLiquidatable() )                     // BAD-FORM: Finds code using code
	{
		value = ((LiquidAsset&)asset).getValue(); // BAD-FORM: Down-cast
 
		((LiquidAsset&)asset).setValue(0);        // BAD-FORM: Down-cast
 
		cout << "Liquidated $" << value << endl;
	}
	else
	{
		value = 0;
		cout << "Sorry, couldn't liquidate this asset.\n";
	}
 
	return value;
}
 
int main()
{
    Asset       a;
    LiquidAsset b;
 
    tryToLiquidate(a);
    tryToLiquidate(b);
 
    return 0;
}

A better way to accomplish this is to give the users of your code the right tools in the first place as member functions, rather than them having to cobble together their own routines in userland:

// C++ FAQS by Cline & Lowom
// FAQ 163 - What is an alternative to using down-casts?
// Answer: An if/down-cast pair can often be replaced by a virtual function call. The key
// insight is to move the -context- of the capability query from the user's code into the
// virtual function; don't just move the primitive query used in the user's if statements.
 
#include <iostream>
using namespace std;
 
class Asset
{
	public:
		virtual ~Asset() { }
 
		virtual int tryToLiquidate()
		{
			cout << "Sorry, couldn't liquidate this asset.\n";
			return 0;
		}
};
 
class LiquidAsset : public Asset
{
	protected:
		int mValue;
 
	public:
		LiquidAsset(int value = 100) : mValue(value) { }
 
		int getValue() const { return mValue; }
 
		void setValue(int theValue) { mValue = theValue; }
 
		virtual int tryToLiquidate()
		{
			int value = mValue;
 
			mValue = 0;
 
			cout << "Liquidated $" << value << endl;
 
			return value;
		}
};
 
int main()
{
    Asset       a;
    LiquidAsset b;
 
    a.tryToLiquidate();
    b.tryToLiquidate();
 
    return 0;
}

Much better =D

Comments
No Comments »
Categories
Coding
Tags
C++, Class, Design, Down-cast, Structure, Virtual Function
Comments rss Comments rss
Trackback Trackback

Gloria Jean’s Cold Drink Recipe List

r3dux | January 30, 2012

Gloria Jean’s is an Australia chain of coffee shops, and they do some great cold drinks like Vanilla Chillers and Tim-Tam Chillers. So here’s a recipe list showing what’s in ‘em.

Gloria Jean's Cold Drinks Recipes

Gloria Jean's Cold Drinks Recipes 2011 - Click for full-size image.

When the recipe calls for filling up to the logo on a cup, this is what the cups looks like so you can get an idea of what they mean:

Gloria Jean's Cup

You’ll have to substitute in things like “Very Vanilla Chiller” powder and “Fruzie Concentrate” – but I’m sure you can find something suitable.

EnJoY! =D

Comments
No Comments »
Categories
Consumer Whore
Tags
Chiller, Cold, Drink, Drinks, Gloria Jeans, Recipe, Sheet
Comments rss Comments rss
Trackback Trackback

Derived class issues with arrays and casting in C++

r3dux | January 29, 2012

I’m working my way through C++ FAQs book by Cline and Lomow, and it’s excellent. There’s lots of issues going on with inheritance, arrays and casting that could be a real pain to deal with towards the end of system development, but that you can nip in the bud and make life easier for yourself. For example, just knowing that an array of objects of a Derived class is NOT a kind-of array of objects of the Base class can prevent you a lot of headaches…

// Book: C++ FAQs by Cline & Lomow
// FAQ 136 & 137 - Is array-of Derived a kind-of array-of Base?
// Answer: NO!
 
#include <iostream>
using namespace std;
 
class Base
{
	protected:
		int i;
 
	public:
		Base() : i(42*42)      { }
		virtual ~Base()        { }
		virtual void service() { cout << "Base::service() called.\n" << flush; }
};
 
class Derived : public Base
{
	protected:
		// Add some extra things so that an object of type Derived is a different
		// size to an object of type Base
		int j;
		float k;
		unsigned long l;
 
	public:
		Derived() : Base(), j(42*42*42) { }
		virtual void service()          { cout << "Derived::service() called.\n" << flush; }
};
 
// Userland function
void useSubscript(Base *b)
{
	cout << "b[0].service(): " << flush; b[0].service();
	cout << "b[1].service(): " << flush; b[1].service(); // BOOM! Segfault!
 
	// This fails because the size of Base and the size of Derived are different:
	// "The fundamental problem is that a pointer to the first of an array-of-things
	// has exactly the same type as a pointer to a single thing. This was inherited
	// from C."
	//
	// In essence, as we're passing in Base pointers, in this case Base moves from
	// element to element in 16 byte intervals, but we actually provided an array
	// of Derived objects, which have a size of 32 bytes each, so b[1] starts
	// at b[0]+16, which is really only half-way through our first Derived element d[0]!
	//
	// The way to do this properly is to use a templatised container class instead.
	// If you tried to pass Array<Derived> as Array<Base> this would be caught at compile time.
}
 
int main()
{
    Derived d[10];
 
    cout << "Base has a size of   : " << sizeof(Base)    << " bytes." << endl;         // 16 bytes
    cout << "Derived has a size of: " << sizeof(Derived) << " bytes." << endl << endl; // 32 bytes
 
    useSubscript(d);
 
    return 0;
}

Good to know – now I just have to keep it in mind when I’m coding!

Comments
No Comments »
Categories
Coding
Tags
Array, Base, C++, Class, Crash, Derived, Kind-Of, Segfault
Comments rss Comments rss
Trackback Trackback

Why is Linux using all my RAM?

r3dux | January 27, 2012

My Linux-running laptop seemed to be a little bit sluggish, so I had a look at the amount of free RAM available – and did a double take:

Linux free RAM confusion

A few apps eating an entire 4GB? Say it ain't so!

This is on a 4GB machine with a web browser (6 tabs) open, email client, code::blocks IDE and totem to play some music. How can that devour my entire 4GB?

Answer: It can’t. Or at least it’s not! The Linux kernel is in fact using free RAM as a disk cache to keep your most often used data in memory and thus speed up the system. As soon as that RAM is actually needed for applications, then it’s instantly made available. This is in theory like the Windows Superfetch service (which is the first thing I disable on any Windows machine I’m forced to co-exist with), only the Linux version actually works well without perpetually thrashing the pants off the hard drive.

What’s really happening is this:

Linux free RAM in reality

It ain't so =D

For the exact workings, please see the excellent (and indeed excellently named) site “Help! Linux ate my RAM!” – http://www.linuxatemyram.com/.

Bit of a PEBKAC moment, there ;-)

Comments
No Comments »
Categories
Linux, Tech
Tags
Cache, Free, RAM, Superfetch
Comments rss Comments rss
Trackback Trackback

Happy Australia Day!

r3dux | January 26, 2012

Australia Day 2012

You can read about the history of Australia Day here, if you’re interested. Or just throw another shrimp on the barbie and be thankful for the day off =D

Comments
No Comments »
Categories
Life
Tags
Aussie, Australia, Australia Day, holiday
Comments rss Comments rss
Trackback Trackback

« Previous Entries

Translate

Categories

Archives

Tags

3D ActionScript ActionScript 3.0 Adobe AI Ballarat Bash C++ Class Convert CS4 Effect Error Film Flash GLSL Gnome Hack How-To install Jaunty Java Kinect Linkage Linux Mash-Up Microsoft Motion OpenGL Particle Problem PS3 Remix Retro script Slides Sound Systems Texture Ubuntu Video VirtualBox Wii Windows XBox

Gamercard

OpenR3dux

Misc.

Flattr this

RSS Feed

r3dux twitter feed



“Dow's Law: In a hierarchical organization, the higher the level, the greater the confusion.”

rss Comments rss valid xhtml 1.1 design by jide powered by Wordpress get firefox