Quick C++ question.

Started by
10 comments, last by dmatter 14 years, 8 months ago
Hi. I was wondering if there is any possible way to do what I am about to describe in C++. And if there is - How? I have a class lets call it A.

class A {
public :
virtual void mem1() =0;
virtual void mem2() =0;
};
I want to create another class B, which is derived from A(public), but I want to redefine a members function, so that it becomes something like this.

class B : public A {
public :
virtual void mem1() 
{
   //Add certain checks
   //Then call mem1 (of it's derived class).
   //Add some more checks
}
};
And now If I create a class C, which is derived from B and I alter the member function "mem1" (Since it's virtual). I still wants those checks to occur. I know one way is the create a new pure virtual member function, and place it inside B's mem1 function, but is there any way I can do this without creating a new function (I basically want the new function to have the same name.) I doubt, this is possible. But I just thought I should ask. Any suggestions ?
Advertisement
EDIT: I misread the question.

Couldn't you just call the mem1 function of the base class when you need to ?
I.e. 'B::mem1()' ? This is perfectly possible in C++.
No, I should have been clearer.
class A {public :virtual void mem1() =0;};class B : public A {public :virtual void mem1(){   std::cout << "Preliminary Checks" << std::endl;   //Call function mem1(), but it should not be recursive,   std::cout << "Post-run checks" << std::endl;}};class C : public B {public :virtual void mem1(){    std::cout << "Hurray !! This is what I wanted" << std::endl;}};C object;object.mem1();


The output should be -
Preliminary ChecksHurray !! This is what I wantedPost-run checks


Do you think this is possible ?

EDIT :
@plastique : Yes, I can. And that is exactly what I'm doing right now. I was just wondering if there was some other way to emulate such behavior. I guess there isn't.
Thanks anyway.
You don't have to call the same function but a different virtual function (and C doesn't override mem1 at all).

Otherwise it is not quite normal that base classes know about classes derived from them.
This is one of the little annoyances of C++. Sometimes you want to ADD to a function's behaviour, not override the parent function entirely. In Java you can refer to "super" or some such thing, and call the parental version from the child, but in C++ you end up hardcoding the parent'sClassName:: to do that, which feels somehow dirty (and is easy to forget to do).

I can think of ways to help automate the process a bit, but they involve really ugly work with #define and wrapping the whole subclass definition in macros, and the more I think about it the less willing I would be to actually do that. Just erect a big, insulting comment explaining that in the case of function X(), the parental version must be called, and anyone that forgets is the benighted offspring of an especially foul, mutant earthworm. It may help people remember.
Yeah, on the one hand that's like assuming the class knows about the derived class, on the other hand trying to have a nested call on an overridden function.

Maybe it would be better to completely rethink the whole task or for starters make those checks public (or protected) member functions which a derived class also is able to call.
It could be done by calling B::mem1 twice from C::mem1 and keeping track of whether B::mem1 has been invoked before to switch between pre and post conditions:

#include <iostream>class A{public:    virtual void mem1() = 0;};class B : public A{public:    B() : first_time(true) { }    void mem1()    {        if (first_time)        {            std::cout << "preconditions\n";            first_time = false; // do postconditions next time        }        else        {            std::cout << "postconditions" << std::endl;        }    }private:    bool first_time;};class C : public B{public:    void mem1()    {        B::mem1(); // preconditions        std::cout << "C::mem1\n";        B::mem1(); // postconditions    }};int main(){    C().mem1();}/*output:preconditionsC::mem1postconditions*/

You could take it a different way and have them recursively invoke each other (using CRTP to avoid B knowing about C expliticly) whilst making sure not to cause an infinite loop.

Neither of these are actually recommended in practice though, using another function is a vastly superior solution:

#include <iostream>class A{public:    virtual void mem1() = 0;};class B : public A{public:    void mem1()    {        std::cout << "preconditions\n";        checked_mem1();        std::cout << "postconditions" << std::endl;    }private:    virtual void checked_mem1() = 0;};class C : public B{private:    void checked_mem1()    {        std::cout << "C::checked_mem1\n";    }};int main(){    C().mem1();}/*output:preconditionsC::checked_mem1postconditions*/
@dmatter : Thanks for your response. The second method is the first thing that popped into my head, and I'm using it right now. I just thought I should research a little before jumping the gun.

@ScottMayo : - "the benighted offspring of an especially foul, mutant earthworm."- Hehe! Good one.

The main reason I wanted to do this was cause I already have class "C" implemented in a couple of places(various different versions), and now I would like to add certain checks and features without editing ever single class. So, I just though I would make a middle class with all those checks and features, and make the C class derive from it instead of from A.
My I suggest the design pattern "template method"? Note that it has nothing to do with C++ templates.

#include <iostream>class A{public:    virtual void mem1() = 0;    // do not forget virtual destructor!!!    virtual ~A() {};};class B : public A{public:    void mem1()    {        std::cout << "sanity check #1" << std::endl;        override_me();        std::cout << "sanity check #2" << std::endl;    }protected:    virtual void override_me() = 0;};class C : public B{protected:    void override_me()    {        std::cout << "in C" << std::endl;    }};int main(){    A* p = new C();    p->mem1();    delete p;}
Quote:Original post by Vish
I just thought I should research a little before jumping the gun.
Always a good idea [smile]

Note a subtle difference between my implementation of the technique and DevFred's, namely that the abstract method (checked_mem1/overide_me) in my example is private but in DevFred's it's protected. The appropriate choice depends on whether classes deriving from C need to be able to call the abstract method directly without enforcing the pre/post conditions, or whether it should always be checked.

This topic is closed to new replies.

Advertisement