Re: Wrong Virtual Function Called
Thanks for all your responses. Several of you mentioned the need to
recompile clients if I changed the virtual interface.
Uli wrote:
Late binding is usually implemented by calling the n-th function in the
classes virtual function table. If you change the meaning of the table
(i.e. index n doesn't mean fou anymore but barre) then your program fails
like you describe.
I assumed the client object vptr pointed to the head of the vtable and
the appropriate function name would be resolved. However it seems as
though the vptr stores information (i.e call n-th function) based on
the vtable layout when the client was compiled. I thought or hoped that
the function name resolution would not need to have prior knoweldge of
the vtable layout.
Anyone know why? If the interface was non-virtual and extended a
rebuild of the client would not be necessary and linking (whether
dynamic or static) would resolve to the correct member function.
Certain clients were not exhibiting erroneous behaviour but this must
be because they were accessing a part of the vtable which has not
altered.
To confirm I believe dynamic linking is correct and resolving to the
correct vtable so this is not the issue. It's the late binding
vptr/vtable implementation mechanism which requires a rebuild of all
clients which instantiate any class in the inheritance hierarchy whose
virtual interface has changed.
I appreciate your comments.
I've included some example code to demonstate this behaviour for
completeness.
// Original Output
DealA::construct()
DealA::validateTrade()
DealA::reference()
// Inclusion of addnew() functions and recompile of shared library only
// showing incorrect output
DealA::construct()
DealA::addnew1()
DealA::addnew2()
/////////////////////////////////////////////////
// Solaris 2.8 Build Commands
/////////////////////////////////////////////////
CC -PIC -g -c test.cpp
ld -G -o libtest.so test.o
CC -g -o testmain testmain.cpp -L/home/reddys/code/cpp -ltest
////////////////////////////////
// test.hpp
///////////////////////////////
#include <iostream>
using namespace std;
class Transaction
{
public:
Transaction() {};
virtual ~Transaction() {};
virtual void construct() = 0;
/***
virtual void addnew1() = 0;
virtual void addnew2() = 0;
virtual void addnew3() = 0;
virtual void addnew4() = 0;
***/
virtual void validateTrade() = 0;
virtual void reference() = 0;
private:
string label;
int value;
};
class DealA : public Transaction
{
public:
DealA();
void construct();
/***
void addnew1();
void addnew2();
void addnew3();
void addnew4();
***/
void validateTrade();
void reference();
};
class DealB : public Transaction
{
public:
DealB();
void construct();
/***
void addnew1();
void addnew2();
void addnew3();
void addnew4();
***/
void validateTrade();
void reference();
};
////////////////////////////////
// test.cpp
///////////////////////////////
#include <iostream>
#include "test.hpp"
using namespace std;
//
// DealA
//
DealA::DealA()
{
}
void DealA::construct()
{
cout << "DealA::construct()" << endl;
}
void DealA::validateTrade()
{
cout << "DealA::validateTrade()" << endl;
}
void DealA::reference()
{
cout << "DealA::reference()" << endl;
}
/***
void DealA::addnew1()
{
cout << "DealA::addnew1()" << endl;
}
void DealA::addnew2()
{
cout << "DealA::addnew2()" << endl;
}
void DealA::addnew3()
{
cout << "DealA::addnew3()" << endl;
}
void DealA::addnew4()
{
cout << "DealA::addnew4()" << endl;
}
****/
//
// DealB
//
DealB::DealB()
{
}
void DealB::construct()
{
cout << "DealB::construct()" << endl;
}
void DealB::validateTrade()
{
cout << "DealB::validateTrade()" << endl;
}
void DealB::reference()
{
cout << "DealB::reference()" << endl;
}
/****
void DealB::addnew1()
{
cout << "DealB::addnew1()" << endl;
}
void DealB::addnew2()
{
cout << "DealB::addnew2()" << endl;
}
void DealB::addnew3()
{
cout << "DealB::addnew3()" << endl;
}
void DealB::addnew4()
{
cout << "DealB::addnew4()" << endl;
}
******/
////////////////////////////////
// testmain.hpp
///////////////////////////////
#include <iostream>
#include "test.hpp"
using namespace std;
int main()
{
DealA *trade = new DealA();
trade->construct();
trade->validateTrade();
trade->reference();
delete trade;
}
simon.reddy@lchclearnet.com wrote:
I have altered the pure virtual interface for a class called
Transaction by adding one pure virtual and removed an existing pure
virtual function.
I have provided definitions for the new pure virtual in three derived
classes and removed traces of the unwanted virtual function. I have
re-built this shared library (Solaris 2.8) with no compilation or
linker errors.
I have also rebuilt a further set of derived classes (database layer)
which inherit from the three derived classes (business layer) and
produced a second shared library. There have been no code changes but
because the base classes have changed I have recompiled the objects.
A client program creates a Transaction object and I am experiencing
core dumps based on the wrong virtual function being called. Other
clients do not exhibit this behaviour indeed the client in question
does resolve some virtual functions correctly but always core dumps at
the same virtual function call
I thought it is not necessary to rebuild the client program if the
virtual interface has changed in a shared library. Late binding should
correctly resolve to the correct function. Any help would be
appreciated.
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]