Object Oriented Programming Tips
By Carey Nachenberg
Before designing your base and derived classes for Project 3 (or for that matter, any other school or work project), make sure to consider the following best practices. These tips will help you not only write a better object oriented program, but also help you get a better grade on P3!
Try your best to leverage the following best practices in your program, but dont be overly obsessive its rarely possible to make a set of perfect classes. Thats often a waste of time. Remember, the best is the enemy of the good (enough).
Here we go!
1. Avoid using dynamic cast to identify common types of objects. Instead add a method to check for a kind of behavior:
Dont do this:
void decideWhetherToAddOil(Actor* p)
{
if (dynamic_cast
dynamic_cast
}
Do this instead:
void decideWhetherToAddOil(Actor* p)
{
// define a common method, have all Robots return true, all biological // organisms return false
if (p->requiresOilToOperate())
p->addOil(); }
2. Always avoid defining specific isParticularClass() methods for each type of object. Instead add a method to check for a kind of common behavior that spans multiple classes:
Dont do this:
void decideWhetherToAddOil(Actor* p)
{
if (p->isGoodRobot() || p->isBadRobot() || p->isStinkyRobot())
p->addOil(); }
Do this instead:
void decideWhetherToAddOil(Actor* p)
{
// define a common method, have all Robots return true, all biological // organisms return false
if (p-> requiresOilToOperate())
p->addOil(); }
3. If two related subclasses (e.g., BadRobot and GoodRobot) each directly define a member variable that serves the same purpose in both classes (e.g., m_amountOfOil), then move that member variable to the common base class and add any necessary accessor and mutator methods for it to the base class. So the Robot base class should have the m_amountOfOil member variable defined once, with, say, getOil() and addOil() methods, rather than defining this variable directly in both BadRobot and GoodRobot.
Dont do this:
class SmellyRobot : public Robot
{
private:
int m_oilLeft;
};
class GoofyRobot : public Robot
{
private:
int m_oilLeft; };
Do this instead:
class Robot
{ public:
int getOil() const { return m_oilLeft; } private:
int m_oilLeft; };
4. Never make any classs data members public or protected. You may make class constants public, protected or private.
5. Dont introduce a public method if it is to be used directly only by other methods within the same class that declares it. Make it private or protected instead.
6. Your StudentWorld methods should never return a vector, list or iterator to StudentWorlds private game objects or pointers to those objects. Only StudentWorld should know about all of its game objects and where they are. Instead, StudentWorld should do all of the processing itself if an action needs to be taken on one or more game objects that it tracks.
Dont do this:
class StudentWorld {
public:
vector
};
// create a vector with a actor pointers and return it }
void addOil(int oil) { m_oilLeft += oil; }
class NastyRobot {
public:
virtual void doSomething()
{
vector
v = studentWorldPtr->getActorsThatCanBeZappedAt(getX(), getY()); for (p = actors.begin(); p != actors.end(); p++)
p->zap();
} };
Do this instead:
class StudentWorld
{
public:
} };
class NastyRobot {
public:
void zapAllZappableActors(int x, int y)
{
for (p = actors.begin(); p != actors.end(); p++)
if (p->isAt(x,y) && p->isZappable()) p->zap();
virtual void doSomething() {
studentWorldPtr-> zapAllZappableActors(getX(), getY()); }
};
7. If two subclasses have a method that shares some common functionality, but also has some differing functionality, use an auxiliary method to factor out the differences:
Dont do this:
class StinkyRobot : public Robot {
virtual void takeAction() {
} };
doCommonThingA(); passStinkyGas(); pickNose(); doCommonThingB();
class ShinyRobot : public Robot {
virtual void takeAction()
{
doCommonThingA();
} };
polishMyChrome(); wipeMyDisplayPanel(); doCommonThingB();
Do this instead:
class Robot {
public:
virtual void takeAction()
{
}
doCommonThingA(); doDifferentiatedStuff(); doCommonThingB();
// all robots do this
// each kind of robot does this differently // all robots do this
private:
virtual void doDifferentiatedStuff() = 0;
};
class StinkyRobot : public Robot {
private:
// define StinkyRobots version of the differentiated function virtual void doDifferentiatedStuff()
{
passStinkyGas();
pickNose(); }
};
class ShinyRobot : public Robot {
private:
// define ShinyRobots version of the differentiated function virtual void doDifferentiatedStuff()
{
// only Shiny robots do these things
polishMyChrome();
wipeMyDisplayPanel(); }
};
Notice that doDifferentiatedStuff() is private, because no methods in other classes should call it directly. It should be private, not protected, in the base class; derived classess overriding a virtual function is not considered to be using the base class version in a way that the public/protected/private distinction matters.
Good luck!
Reviews
There are no reviews yet.