1

First, let me preface this question with "I am new to C++"! This will probably turn out to be something very simple and I'll feel pretty dumb but right now I could really use the help. I know how to do this with an Abstract class but I can't use an Abstract class here. Also, if there is a better way to do this, I'm open to suggestions.


I have a ClientCommand (base class) and a MasterCommand (extends base class)

enter image description here

The MasterCommand can do everything that the ClientCommand can do and a few more methods.

In my application, I want to use the same name for both commands. If the object is a Client then it will be limited to only client methods. If the object is a Master then it will have all the client methods plus the Master methods.

I know there has got to be a way to do this.

  1. I am not casting it correctly
  2. I am not constructing it correctly
  3. Or there is something else I'm doing wrong

Here is my test code:


BASE CLASS HEADER:

#ifndef __OPCommand_H_
#define __OPCommand_H_

class OPCommand {

public:
    virtual void doSomething();
    void doClientStuff();
};

#endif //__OPCommand_H_

BASE CLASS BODY:

#include "OPCommand.h"

void OPCommand::doSomething() {
    // TODO - implement OPClientCommand::doSomething
    throw "Not yet implemented";
}

void OPCommand::doClientStuff() {
    // TODO - implement OPClientCommand::doClientStuff
    throw "Not yet implemented";
}

EXTENDED CLASS HEADER:

#ifndef __OPMasterCommand_H_
#define __OPMasterCommand_H_

#include "OPCommand.h"

class OPMasterCommand : public OPCommand {

public:
    void doSomething();
    void doMasterStuff();
};

#endif //__OPMasterCommand_H_

EXTENDED CLASS BODY:

#include "OPMasterCommand.h"

void OPMasterCommand::doSomething() {
    // TODO - implement OPMasterCommand::doSomething
    throw "Not yet implemented";
}

void OPMasterCommand::doMasterStuff() {
    // TODO - implement OPMasterCommand::doMasterStuff
    throw "Not yet implemented";
}

TEST CLASS HEADER:

#ifndef __TestMe_H_
#define __TestMe_H_


#include "OPMasterCommand.h"
#include "OPCommand.h"

class TestMe {

public:
    OPCommand* command;
    OPMasterCommand* masterCommand;

public:
    void startHere();
    OPMasterCommand* getMasterCommand();
    OPCommand* getCommand();
    bool isMaster();

};

#endif //__TestMe_H_

TEST CLASS BODY:

Pay close attention to the startHere method:

#include "TestMe.h"

void TestMe::startHere() {
    if (isMaster()) {
        masterCommand = getMasterCommand();
    } else {
        command = getCommand();
    }

    // Here - How can I point to or cast to the appropriate type, so I can use the same name everywhere in my code?

}

OPMasterCommand* TestMe::getMasterCommand() {
    if (!masterCommand) {
        masterCommand = new OPMasterCommand();
    }
    //command = dynamic_cast<OPCommand*> (masterCommand);
    return masterCommand;
}

OPCommand* TestMe::getCommand() {
    if (!command) {
        command = new OPCommand();
    }
    return command;
}

bool TestMe::isMaster() {
    return true;
}

I cannot get this to build. Right now I'm getting a redefinition of 'OPCommand'

Patricia
  • 5,019
  • 14
  • 72
  • 152
  • Please show the diagram of the desired class heirarchy. –  Mar 09 '15 at 16:11
  • First off, please show the complete error message, and the affected line. Also, looks like you are including OPCommand.h twice in TestMe, and don't have a guard define in OPCommand.h – OldProgrammer Mar 09 '15 at 16:13
  • 1
    Also, you need ifndef/define/#endif in the "command" headers. –  Mar 09 '15 at 16:13
  • @Arkadiy - ifndef/define/#endif in the "command" headers made the errors go away, so now I am building. – Patricia Mar 09 '15 at 16:20
  • ok, then - problem solved? Or do you still need a different class diagram? –  Mar 09 '15 at 16:24
  • @Arkadiy - I am sorry but there's nothing more to show in the desired class hierarchy. I just created the test project to instantiate the masterCommand if master else clientCommand. But I want to use the same name in my code (i.e., cmd). The problem arises because there are two different types, OPClientCommand and OPMasterCommand. How can I make cmd be either class? – Patricia Mar 09 '15 at 16:30
  • 1
    Usually, when you have Command pattern, you have a single Command::doSomething() and 3 command classes: ClientCommand, MasterCommand and OtherCommand. Then you access all 3 via Command reference/pointer. Or you can add a Composite, combining Client and Common under 1 Command –  Mar 09 '15 at 16:38
  • @Arkadiy - You are 100% correct. The problem is that because MasterCommand is a ClientCommand (by extension). If I create an Abstract command then I end up with multiple inheritance and a sort of circular dependency. – Patricia Mar 09 '15 at 16:42
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/72587/discussion-between-arkadiy-and-lucy). –  Mar 09 '15 at 16:43

2 Answers2

2

My psychic debugging skills tell me that since you're new to C++ you forgot your header include guards (that's a very common reason for the redefinition of 'OPCommand' error you're seeing).

Try putting something like this (changing the names for each header) in your header files:

#ifndef OPCOMMAND_H_included
#define OPCOMMAND_H_included

<original header contents>

#endif
Mark B
  • 95,107
  • 10
  • 109
  • 188
  • 1
    Or if the compiler is recent enough `#pragma once` – RedX Mar 09 '15 at 16:17
  • @FredLarson: I think those answers fail to mention the big problem with `#pragma once`. See http://stackoverflow.com/questions/23696115/is-pragma-once-part-of-the-c11-standard for when `#pragma once` may fail. – Christian Hackl Mar 09 '15 at 16:20
  • 1
    @RedX: It's not so much a question of whether the compiler is recent enough. `#pragma once` cannot be implemented correctly in all situations, whereas traditional include guards are always safe. See the link I posted above. – Christian Hackl Mar 09 '15 at 16:23
  • Hey, Mark: Thanks for the tip, you're right. But my real question is I want to use the same name in my code (i.e., cmd). The problem arises because there are two different types, OPClientCommand and OPMasterCommand. How can I make cmd be either class? – Patricia Mar 09 '15 at 16:32
1

To answer the second part of the question: How to use a single base class and a single variable for all commands?

You need to look up the Command pattern. In your case, you need to derive all of your classes from Command.

Also, if you derive MasterCommand from ClientCommand, there is no need for multiple inheritance: Command <= ClientCommand <= MasterCommand , that's it. MasterCommand isa Command because it's a subclass of ClientCommand.