tags:

views:

51

answers:

3

I'm having issue with calling a method with l-value of an abstract class. The class definition is:

class SimulatorSequenceItemBase {
public:
    SimulatorSequenceItemBase();
    virtual ~SimulatorSequenceItemBase();

    virtual uint32_t GetResult(uint32_t p_nSite) = 0;
    virtual bool MoveNext(SimulatorSequenceItemBase& p_rNext) = 0;
}

SimulatorSequenceItemBase has multiple sub classes. There are sequences (for loops) and items for within the for loop.

I want to loop through the sequence and count the steps, using:

uint32_t nI = 0;
SimulatorSequenceItemBase root = forSeq; // forSeq is an instance of a subclass of SimulatorSequenceItemBase 
while(root.MoveNext(root))
{
    ++nI;
    std::cout << root.GetResult(0);
}

The root initally references to the root, and on every call to MoveNext, the reference should be adjusted to the next element.

The code mentioned above does not work, because root cannot be allocated, as the type of root is abstract. But if I'd make root a pointer, then the value cannot be altered in MoveNext.

How can I fix this? It's OK to change any code, but the idea should stay the same.

+2  A: 

I have no idea what forSeq is supposed to be, but what's wrong with

SimulatorSequenceItemBase& root = forSeq; // note that &

Since, according to a comment, you need to reset root to refer to different objects, you will have to use pointers:

SimulatorSequenceItemBase* root = forSeq; note the *
while(root.MoveNext(root))
{
    // ...
}

However, in order to have MoveNext() reset root, it has to take the pointer per reference:

bool MoveNext(SimulatorSequenceItemBase*& p_rNext) // note the *&
sbi
@sbi: according to literature: "Once initialized, the refrence itself cannot be made to refer to anything else." (C++ Pocked Reference - Kyle Loudon - O'Reilly), meaning that this would not work for me, as I want to defer root to various element over iteration.
Excel20
@Excel20: Your code didn't show that you wanted `root` to refer to different objects. If you need to do this, you'll need to use a pointer. I'll edit my answer.
sbi
A: 

OK, first of all. Why does MoveNext take an argument at all? It shouldn't.

virtual bool MoveNext() = 0;

and then

SimulatorSequenceItemBase& root = forSeq;
while(root.MoveNext())
{
   ++nI;
}
Armen Tsirunyan
+1  A: 

The reason you've got a problem is because the line SimulatorSequenceItemBase root = forSeq; is actually creating a new instance of SimulatorSequenceItemBase on the stack (a spliced copy of forSeq). Because you have a pure virtual function, you can't create an instance of the base class. What you need to do is change it to use a reference or a pointer:

SimulatorSequenceItemBase *pRoot = &forSeq;

while (pRoot->MoveNext(pRoot))
{
    ++nI;
    std::cout << pRoot->GetResult(0);
}

Edit Following your comment, I suggest refactoring your code to be something like this:

SimulatorSequenceItemBase *pNode = &forSeq;
while (pNode != NULL)
{
    ++nI;
    std::cout << pRoot->GetResult(0);

    pNode = pNode->MoveNext();
};
Mark Ingram
@Mark Ingram: according to literature: "Once initialized, the reference itself cannot be made to refer to anything else." (C++ Pocked Reference - Kyle Loudon - O'Reilly), meaning that this would not work for me, as I want to refer root to various element over iteration.
Excel20
In that case use a pointer, as they can refer to other variables afterwards (I've updated my answer).
Mark Ingram
@Mark Ingram: if you'd leave the parameter out, one would assign the pointer of the next element to 'this'?
Excel20
You wouldn't, see my updated answer for a clearer way of doing what you want.
Mark Ingram