Solved

Determined if a virtual function is overloaded

Posted on 1998-12-18
31
171 Views
Last Modified: 2013-11-18
Given a base class pointer to an object that may be of a derived class, is there a way to determine if the object has overidden a particular virtual function without calling that function.  (And without calling some sort of virtual querry function that the programmer hardcodes to indicate if the function has been overidden--I want something automatic.)  I have been fooling with trying to get a pointer to member for the virtual function, but so far nothing I've tried has been successful--syntax errors.
0
Comment
Question by:nietod
  • 9
  • 8
  • 5
  • +4
31 Comments
 
LVL 8

Expert Comment

by:Answers2000
ID: 1180466
I believe this is compiler specific

Depending on the compiler you use, you may be able to look at the object data and see.  I don't know a generic way to do this.
0
 
LVL 86

Expert Comment

by:jkr
ID: 1180467
Hmm, this should work if you check the vtable entries, e.g.:

if ( &CMyClass::VirtMethod == &CBaseClass::VirtMethod)
{
// not overridden...
}

0
 
LVL 22

Author Comment

by:nietod
ID: 1180468
I definitely want something portable and legal.  No virtual table exploration.  
0
 
LVL 22

Author Comment

by:nietod
ID: 1180469
jkr,
That might work  if I needed to know if a particlar class, like CMyClass, had overidden a function.  (I don't know if it works for that even.)  But my case is slightly different.  I need to know if an object is of a class that does so.  So I have a pointer to an object (might be of type CMyClass, might be something else) and any attempt to get a pointer to this virtual function yields a syntax error.  Could be I haven't found the right syntax, could be it doesn't exist.
0
 
LVL 3

Expert Comment

by:Norbert
ID: 1180470
jkr what you say is a good idea
if I understand nietod right he has something like
class A
{...
     virtual SomeType SomeFunction(SomeParameters);
.}
class B:public class A
{...
     virtual SomeType SomeFunction(SomeParameters);
.}
class C:public class A
{...
.}

GlobalFunction(A* Ptr)
{
   // here he wants to know if function is overwritten
  // I did not try but I know no reason why it should not work
  if(&Ptr->SomeFunction==&A::SomeFunction)
  {
  // not overwridden...
  }
}
and that has nothing to do with virtual table exploration


0
 
LVL 22

Author Comment

by:nietod
ID: 1180471
That's exactly what I was saying--only 10 times clearer.

The problem is that  "&Ptr->SomeFunction" doesn't compile.  I get "illegal operaton on a bound member function."  Various parenthesis didn't help either.  That error message suggests that this may be more of a language constaint than a syntax issue.  But I'm not positive yet.
0
 
LVL 3

Expert Comment

by:Norbert
ID: 1180472
only a guess:
 sometimes by mistake i write
if(ptr->SomeFunc)
insted of
if(prt->someFunc())
the compiler compiles that with no error
perhaps
if(Ptr->SomeFunc==A::SomeFunc)
works

an other guess
which part of the condition lets the compiler fail ?
&Ptr->SomeFunc
or
&A::SomeFunc
maybe its on A::SomeFunc
The compiler may be can't Interpret that
A::SomeFunc has no instanciation and its virtual

perhaps the Following then works:
GlobalFunction(A* Ptr)
{
   A Dummy;
  if(&Ptr->SomeFunction==&Dummy.SomeFunction)
  {
  // not overwridden...
  }
}

PS: Sorry for answerring but I am on vacation for the next three weeks and if that above works and you ask me to answer you have a open question for above three weeks - I am not sure how long the period is until the question is auto deleted
0
 
LVL 86

Expert Comment

by:jkr
ID: 1180473
Well, though i am late, what i said is absolutely portable and legal (simply pointers to member functions!!!)
BTW Pointers to members can only be used in conjunction with instances of the class (for an example, see 'http://www.codeguru.com/win32/dyndllclass.shtml')
0
 
LVL 11

Expert Comment

by:alexo
ID: 1180474
Doesn't work.
Ask Yonat...
0
 
LVL 22

Author Comment

by:nietod
ID: 1180475
jkr, your solution doesn't work because I don't knwo what class I'm working with.  Seee my response above.

I suspect that norbert's isn't any better, but I will try to be sure.

Alex, you sound very confident do you know something I don't?  (well, probably lots but...)
0
 
LVL 86

Expert Comment

by:jkr
ID: 1180476
nietod, unless you don't have the header files for both the derived and the base class, you know about them. Check out the example URL, it definitively works ;-)
To the 'object' problem:
Pointers to members can only be used with a 'clumsy' syntax, e.g.

class CMyClass
{
public:
 void VoidMemberTakingNothing(){};
};

typedef void ( CMyClass::*PMYCLASSMETHOD)();
CMyClass c;

PMYCLASSMETHOD p = &CMyClass::VoidMemberTakingNothing;

(c.*p)();

(But better see the URL, it's elaborated a bit more there... ;-)

0
 
LVL 11

Expert Comment

by:alexo
ID: 1180477
>> Alex, you sound very confident do you know something I don't?
Huh?  I made two comments: that the currently suggested solution doesn't work and that you should ask Yonat because she knows more about C++ than any other EE expert.  True, I'm very confident about both statements but you do know them to be true.
0
 
LVL 4

Expert Comment

by:pagladasu
ID: 1180478
nietod,
I have worked out a solution this way. I have compiled and executed it with a VC++ compiler and it works. Here is the code

#include <stdio.h>
class oo{
public:
      virtual int a(){return 0;}
};
typedef int (oo::*f1)();
f1 baseptr=&oo::a;
class pp:public oo{
public:
      int a(){return 0;}
};
typedef int (pp::*f2)();
f2 childptr=&pp::a;

main(){
oo *ptr=new oo;
if(baseptr==ptr->a)
      puts("DADDY");
ptr=new pp;
if(childptr==ptr->a)
      puts("KID");
return 0;
}

Hope it helps. Thanks
pagladasu
0
 
LVL 11

Expert Comment

by:alexo
ID: 1180479
Doesn't work right.

Try the following:

    ptr = new pp;

    if (baseptr == ptr->a)
        puts("DADDY");

    if (childptr == ptr->a)
        puts("KID");

Both cases evaluate as true.
0
 
LVL 22

Author Comment

by:nietod
ID: 1180480
Alex, that's exactly what I was going to say.  Two pointer to members are  the same when they evaluate to the same member, not necessarily a member with the same "value".  Thus in these examples they all evaluate to the same virtual function member.  (Same offset in the virutal function table.)
0
Free Trending Threat Insights Every Day

Enhance your security with threat intelligence from the web. Get trending threat insights on hackers, exploits, and suspicious IP addresses delivered to your inbox with our free Cyber Daily.

 
LVL 11

Expert Comment

by:alexo
ID: 1180481
Did you try comp.lang.c++.moderated?  That group is full of members of the C++ ISO commitee and even Bjarne frequents it.
0
 
LVL 86

Expert Comment

by:jkr
ID: 1180482
Well, i checked my suggestion (still a bit different ;-), but it doesn't work either...
Just again - i thought of using something like this:

#include <stdio.h>

class CSimple
{
public:
    CSimple ()  {};
    ~CSimple    ()  {};

    virtual void    VirtMeth    ()  {   printf  (   "base virtual method\n");};
};

class CDerivedOnly: public  CSimple
{
public:
    CDerivedOnly    ()  {};
    ~CDerivedOnly   ()  {};
};

class CDerivedAndOverridden:    public  CSimple
{
public:
    CDerivedAndOverridden   ()  {};
    ~CDerivedAndOverridden  ()  {};

    virtual void    VirtMeth    ()  {   printf  (   "derived virtual method\n");};
};


void    main    (   void)
{
    CSimple                 cs;
    CDerivedOnly            cdo;
    CDerivedAndOverridden   cda;

     cs.VirtMeth    ();
    cdo.VirtMeth    ();
    cda.VirtMeth    ();

    if  (   &CSimple::VirtMeth  ==  &CDerivedOnly::VirtMeth)
            printf  (   "virtual method NOT overridden\n");
     else
            printf  (   "virtual method overridden\n");
           
    if  (   &CSimple::VirtMeth  ==  &CDerivedAndOverridden::VirtMeth)
            printf  (   "virtual method NOT overridden\n");
     else
            printf  (   "virtual method overridden\n");
}

As i said, doesn't work, i just wanted to contribute it as an addition ...
0
 
LVL 11

Expert Comment

by:alexo
ID: 1180483
I'm inclined to say that there is no portable way of doing it.
0
 
LVL 86

Expert Comment

by:jkr
ID: 1180484
I'm inclined to agree...
0
 
LVL 4

Expert Comment

by:pagladasu
ID: 1180485
Basically, I think the problem lies in the fact that there is no clear-cut direct way to obtain the address of a virtual function.
0
 
LVL 5

Expert Comment

by:yonat
ID: 1180486
I don't know how to do this, so I'll use my usual strategies in cases like this:
1. Explain why the usual solutions do not work (some C++ mechanics).
2. Throw more objects and classes at the problem.
3. Question the question (my usual "do you really want to do that?" routine).

1. Why the usual solutions do not work.
A pointer to a virtual member function is usually implemented as an offset in the vtable, so it's not really a pointer at all. The only thing you can do with this offset, is use it with a specific object to invoke the member function, but not to get the function's address. Non-portably, you can get the address of the vtable for a specific object, add the offset, and check what's there. But I know of no portable way to do this.

2. Throw more objects and classes at the problem
You can replace the member function with a function object ("functor" or "command object").

3. Question the question
Why do you need to know if the function is overridden? Are you violating the Liskov substitution principle?
The "legal" answer for this is "I really need reflection, because I'm writing a library for XXX". So what's XXX? Is it possible to do without reflection? (tradeoffs, tradeoffs…)

0
 
LVL 22

Author Comment

by:nietod
ID: 1180487
Thanks,  

The reason I am asking this is I have a case where derived classes can handle a group of "notifications" from  base class by implenting a virtual function.  If they chose to handle the notification (overide the virutal function) then there is some "common tasks" that need to be performed at the start and end of the processing, but if they don't choose to override the function, those task should not be performed.  

I can let the overide function call procedures to perform these common tasks, but this is for a library and If a programmer forgot...it would be bad.  In addition, with this sort of approach, a derived class could not call a base class's version of the function to do some of the processing as it would call the "common code" again.  

I want to try to make this as idiot proof as possible as there will be many idiots using the library--and I'll be one of them.

I did not think of using a functor for this because this actually is for a functor (of sorts--I guess it is a "fancy functor").  It has posibilities, but I may just "give up" and require the programmer to be a little more careful.
0
 
LVL 5

Expert Comment

by:yonat
ID: 1180488
This seems appropriate for a functor. Something like:
if (itsFunctor) {
    InitStuff();
    itsFunctor();
    CleanupStuff()
}

The user-programmer writes the a functor and passes it to the constructor or some other way.

But here is a semi-portable code (it will probably work as-is on many compilers, but it may just as well may break on others - I would advise against using it).

template <class BaseClass>
void* GetVirtualFuncPtr(    // non portable!
    const BaseClass& object,
    unsigned memberFuncIdx)
{
    // Find the pointer to the vtable
    // (assume it's at the beginning of the object and that
    // its length is the same as size_t)
    size_t vptr = *( reinterpret_cast<const size_t*>(&object) );

    // Look at the vtable as a simple array of function pointers
    typedef void (*FuncPtr)();
    FuncPtr* vtable = reinterpret_cast<FuncPtr*>(vptr);

    return vtable[memberFuncIdx];
}


template <class BaseClass, class DerivedClass>
bool OverridesVirtualFunc(
    const BaseClass& baseObject,
    const DerivedClass& object,
    unsigned memberFuncIdx)
{
    static void* basefptr = GetVirtualFuncPtr(baseObject, memberFuncIdx);
        // static is only an optimization
   
    const BaseClass& derivedObject = object;
        // ensures DerivedClass is derived from BaseClass,
        // and also handles multiple inheritence
   
    void* fptr = GetVirtualFuncPtr(derivedObject, memberFuncIdx);
    return (fptr != basefptr);
}


class Base
{
public:
    virtual void Foo()
    {
        int x = 7;
        ++x;
    }
};

class NotOverrides : public Base
{
};

class Overrides : public Base
{
public:
    void Foo()
    {
        int y = 42;
        --y;
    }
};


#include <cassert>

int main()
{
    const unsigned cBaseFooIndex = 0; // fragile whenever Base changes
   
    Base b;
    NotOverrides no;
    Overrides o;

    assert( false == OverridesVirtualFunc(b, b, cBaseFooIndex) );
    assert( false == OverridesVirtualFunc(b, no, cBaseFooIndex) );
    assert( true == OverridesVirtualFunc(b, o, cBaseFooIndex) );

    return 0;
}

0
 
LVL 11

Expert Comment

by:alexo
ID: 1180489
>> Look at the vtable as a simple array of function pointers
Are there any compilers which break this assumption?
0
 
LVL 5

Expert Comment

by:yonat
ID: 1180490
Probably. Also, this may work for some compilation options and break for others. Here are a few reasons for this to break, off the top of my head:

- The vtable may contain the RTTI stuff, and not only the pointers to the virtual functions. If the length of the RTTI stuff is constant, then you can cover up for it by adjusting the memberFuncIdx, though.
- The vtable may be near/far while regular pointers to functions are far/near. (this is not a dead issue - it is still important in many embedded systems. It may also be important in 64-bit architectures.)
- The vtable is in a different component (like a DLL or something) and so contains a special kind of reference which is different from a normal pointer. (OK, I'm letting my imagination run wild...)

In any case, the standard does not guarntee anything about the vtable, so you can't rely on it being one thing or another.
0
 
LVL 22

Author Comment

by:nietod
ID: 1180491
After considerable thought--well not THAT considerable, I've given up on this approach, I've decided to place the burden on getting this right on the programmers that use the library.  (That's what programming docs are for anyways.)

Since, Norbert's answer(s) was not right, I'm rejecting it.  Althought I'm not using Yonat's answers, I think they were the best, so I'd like you to answer.

They reason I'm not using that approach was that I am trying to consolidate things to reduce the number of classes and types in my library (where reasonable) in an effort to give VC a hand in compiling.  (My goal is to get it to compile the library in less time than it took to write it!)  So I had collected a bunch of function pointers that perform related tasks (fucntion pointers left over from my Pre C++ days) into a single "Functor" class that contained several virutal functions.  I don't want to add real functors to this class as, I'm leaving on vacation for a week and I'm hopping it can compile the 80,000 lines or so, while I'm gone.  
0
 
LVL 5

Accepted Solution

by:
yonat earned 50 total points
ID: 1180492
Thanks for the points. And it seems giving up on this is the right choice in this case. (You can always add functors later... :-)
0
 
LVL 11

Expert Comment

by:alexo
ID: 1180493
Todd, just an idea, see if you can modify this to do what you need.

class Base
{
public:
    void DoSomething(); // Do not override!

private:
    virtual void ActualOperation() {} // Users can override this one.
};

void Base::DoSomething()
{
    // Do startup processing...
    ActualOperation();
    // Do cleanup processing...
}

Users will provide customized private ActualOperation() methods.
0
 
LVL 22

Author Comment

by:nietod
ID: 1180494
I have that design in numerious places  (that is probably the way a majority of my virtual functions are used)  The problem is--and this is the first time I've encountered it--the Start-up and clean-up need to be done only if the ActualOperation() does something  (The base class version does nothing.)
0
 
LVL 11

Expert Comment

by:alexo
ID: 1180495
Insert an intermediate class that users will derive from.
0
 
LVL 22

Author Comment

by:nietod
ID: 1180496
yeah, with another virtual function for them to actually use rather than the first one.

Of course, that's one more class in an effort to minimize the number of classes...
0

Featured Post

How your wiki can always stay up-to-date

Quip doubles as a “living” wiki and a project management tool that evolves with your organization. As you finish projects in Quip, the work remains, easily accessible to all team members, new and old.
- Increase transparency
- Onboard new hires faster
- Access from mobile/offline

Join & Write a Comment

Suggested Solutions

Introduction Knockoutjs (Knockout) is a JavaScript framework (Model View ViewModel or MVVM framework).   The main ideology behind Knockout is to control from JavaScript how a page looks whilst creating an engaging user experience in the least …
Container Orchestration platforms empower organizations to scale their apps at an exceptional rate. This is the reason numerous innovation-driven companies are moving apps to an appropriated datacenter wide platform that empowers them to scale at a …
The viewer will learn how to look for a specific file type in a local or remote server directory using PHP.
The viewer will learn how to pass data into a function in C++. This is one step further in using functions. Instead of only printing text onto the console, the function will be able to perform calculations with argumentents given by the user.

705 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

21 Experts available now in Live!

Get 1:1 Help Now