Hey I think u can pass a const reference to a derived virtual function.
I tried with it and it works fine
Post some example of your code, so that we can investigate
Main Topics
Browse All TopicsI found a strange error I don't really understand. I have a derived class with a virtual function. The second parameter to the call was a const reference to a class I defined in a separate dll. When compiling and debugging it I found out that inside the function not the address of the variable was known to the function but the address of the vftable of that class was used instead. Not only the values where different but even the stack got corrupted (__chkesp failed). Just buy chance I removed the reference and now everything works as expected. When am I allowed to pass a variable which doesn't change as const and by reference? At least in a copy contructor I am.
This Question has been solved and asker verified All Experts Exchange premium technology solutions are available to subscription members.
Experts Exchange has been collecting answers to technology questions since 1996…3 million and counting! If you have a question, chances are we already have your answer.
If you can't find the exact answer you're looking for, ask our exclusive community of 50,000 experts. You’ll get a personalized answer from a trusted professional.
Thousands of free tech tips, tricks, how-to’s and tutorials are available in our peer reviewed articles section. See for yourself how smart our experts are, no login required.
Access the answers to your technology questions today.
30-day free trial. Register in 60 seconds.
Members of the expert community talk about why the experience at Experts Exchange is different than what you will find anywhere else.

Try it out and discover for yourself.
30-day free trial. Register in 60 seconds.
Join the community of experts here and help other tech pros by answering question in your area of expertise. You can earn FREE access to all Experts Exchange's premium features and resources.
The class definition for the object to be passed is
class COORDDLL_API WorldCoord
{
public:
[snip]
WorldCoord();
WorldCoord (const WorldCoord& wcPos);
WorldCoord (double du, double dv, double dw);
//WorldCoord (const WORLD_COORD mcPos);
virtual ~WorldCoord();
WorldCoord& operator= (const WorldCoord &wcPos);
double m_dU;
double m_dV;
double m_dW;
};
The virtual class definition with the function is
class WorldCoord;
class FitObj
{
public:
FitObj () {};
virtual ~FitObj () {};
virtual void ToWorldFit (WorldCoord& wcPos, const WorldCoord wcAct, const double dPhi = 0) = 0;
virtual void SetPhi (double dPhi) = 0;
virtual void SetCamPos (const WorldCoord wcPos) = 0; // for sensor camera 1 pos and for chip rotation center
virtual void SetOffset (const WorldCoord wcPos) = 0; // for sensor offset from global center and for chip offset from rotation center
virtual void SetChi2 (const double dChi2) {m_dChi2 = dChi2; return;};
virtual double GetChi2 (void) {return m_dChi2;};
protected:
double m_dChi2;
};
And the actual class calling the function:
typedef list<MotorCoord> MList;
typedef list<WorldCoord> WList;
#include "FitObj.h"
class CSensor : public FitObj// : public CObject
{
public:
virtual void ToWorldFit(WorldCoord& wcPos, const WorldCoord wcAct, const double dPhi = 0); // virtual from class FitObj
[snip]
void ToSensor(WorldCoord& wcPos, const WorldCoord wcAct, const double dPhi = 0);
void ToSensor(WorldCoord& wcPos, const double dPhi = 0);
void ToWorld(WorldCoord& wcPos, const WorldCoord wcAct, const double dPhi = 0);
void ToWorld(WorldCoord& wcPos, const double dPhi = 0);
void FitCoord (int n);
CSensor();
virtual ~CSensor(); // virtual from class FitObj
protected:
MotorCoord m_mcFirst;
list<LONG> m_clChipRot; //< list of rotation angles of chips
WList m_clChipPos; //< list of points to place chips
WList m_clRef; //< list of reference points on sensor
MList m_clCoord; //< list of measured motor coords of ref points
POINT m_pPtsFrame[5]; //< list of border frame points.
MotorCoord m_mcToHead;
MotorCoord m_mcMeasPos;
WorldCoord m_wcOffset;
double m_dPhi;
};
The function call with the problem was
virtual void ToWorldFit(WorldCoord& wcPos, const WorldCoord& wcAct, const double dPhi = 0); // virtual from class FitObj
When called via
fpFitObj->ToWorldFit (wcPos, wcAct, phik); // wcAct = cam1pos // for CChip +phik is correct solution!
where fpFitObj is a pointer to the class FitObj.
Looks OK except the line:
public:
virtual void ToWorldFit(WorldCoord& wcPos, const WorldCoord wcAct, const double dPhi = 0); // virtual from class FitObj
there is no & after const WorldCoord (I beleive this is typo).
So, when you call this function, it fails. And When you replace with:
virtual void ToWorldFit(WorldCoord wcPos, WorldCoord wcAct, const double dPhi = 0); // virtual from class FitObj
it works?
No I first tried it with
virtual void ToWorldFit(WorldCoord& wcPos, const WorldCoord& wcAct, const double dPhi = 0);
in FitObj and CSensor and this gave problems that inside CSensor::ToWorldFit () the address of wcAct was the WorldCoord::vftable instead of the address. I tried afterwards the version:
virtual void ToWorldFit(WorldCoord& wcPos, const WorldCoord wcAct, const double dPhi = 0);
and then everything is working correct. But I don't really understand why I can't use the first function.
Whatever code u have, I have simulated it into a simpler version.
Just go thru this, this code works fine
===========
#include <iostream>
#include <stdlib.h>
using namespace std;
class Obj {
} ;
class A {
public :
virtual void f ( const Obj &p ) {
cout << "\nIn A" ;
}
} ;
class B : public A {
public :
void f ( const Obj &p ) {
cout << "\nIn B" ;
}
} ;
int main(int argc, char *argv[])
{
A *aPtr ;
A aObj ;
B bObj ;
Obj o ;
// Ptr points to an object of type A
aPtr = &aObj ;
aPtr -> f ( o ) ;
// Ptr points to an object of type B
aPtr = &bObj ;
aPtr -> f ( o ) ;
system("\nPAUSE");
return 0;
}
=================
Since WorldCoord is a virtual class, your functions should pass the value by reference or pointer.
So it should be the following:
virtual void ToWorldFit(WorldCoord& wcPos, const WorldCoord& wcAct, const double dPhi = 0);
Here's an example of what happens when you pass a virtual class by value compared to what you get when you pass by reference.
class foo
{
public:
foo(){x=2;}
virtual ~foo(){}
virtual int GetValue(){return x;}
int x;
};
class foo_decs : public foo
{
public:
foo_decs(){y=3;}
~foo_decs(){}
int GetValue(){return x+y;}
int y;
};
void SomeFunction_bad_via_value
{
cout << f.GetValue() << endl << endl;
}
void SomeFunction_good_via_ref(
{
cout << f.GetValue() << endl << endl;
}
void SomeFunction_good_via_ptr(
{
cout << f->GetValue() << endl << endl;
}
int main(int argc, char* argv[])
{
foo_decs fd;
SomeFunction_bad_via_value
SomeFunction_good_via_ref(
SomeFunction_good_via_ptr(
system("pause");
return 0;
}
In the above code, foo_decs has over writen the GetValue function, so it should return a 5
However, when foo_decs object is passed to SomeFunction_bad_via_value
When ever you have a virtual class, you should always setup you're functions to pass the class by reference or by pointer.
Hi Axter,
I think your example illustrates a good point, but u have decalred a variable of type of derived class
However the real benefit of virtual functions appear when we declare a pointer of base class point to object of either the base of derived class.
Also, his code also signifies the same thing.
I tried to simulate his example by simple classes, I think it works fine
I have pasted the code above
@Axter,
No WorldCoord is not a virtual class. FitObject is a pure virtual class and CSensor is the class derived of. WorldCoord is a class which is inside a DLL.
@Sys_Prog
I assumed that I can pass a const ref but why does it fail here?
@all:
I tried using
virtual void ToWorldFit(WorldCoord& wcPos, const WorldCoord& wcAct, const double dPhi = 0);
Now inside CSensor::ToWorldFit () wcAct is not properly passed. In the debugger I look at &wcAct and it shows
00384100 WorldCoord::`vftable` instead of something line 0012e15c (a memory location on the stack). And more severe I get the error message that ESP has not been saved correctly around a function call. All this disappears when I just change the function definition to
virtual void ToWorldFit(WorldCoord& wcPos, const WorldCoord wcAct, const double dPhi = 0);
and recompile.
Where can I look for the reason?
Hi SteH
I cannot figure out any problem with your code
As u know, I have coded the same thing in a simpler/illustrative way
Below is an exact replica of the situation in your code
Also regarding the value while debugging, I tried with both of the approaches - value and reference, in both ways, it shows me the same thing in debug
I think some issue with the compiler
Which one are u having
I am using a GNU compiler
===
#include <iostream>
#include <stdlib.h>
using namespace std;
class Obj {
} ;
class A {
public :
virtual void f ( const Obj &p ) = 0 ;
} ;
class B : public A {
public :
void f ( const Obj &p ) {
cout << "\nIn B" ;
}
} ;
int main(int argc, char *argv[])
{
A *aPtr ;
B bObj ;
Obj o ;
// Ptr points to an object of type B
aPtr = &bObj ;
aPtr -> f ( o ) ;
system("\nPAUSE");
return 0;
}
=======
I m using MS VC++ 6.0 with SP5. I have some other places where I can pass arguments as const refs. Escpecially copy constructors need it. But even other functions don't fail that badly. Could it be project/compiler settings used for the main app and the dlls? Some code has to reside in a DLL to avoid name conflicts with MFC. Maybe compiler/linker switches could be wrong but I tried to get them all identical. Any hints here?
>>No WorldCoord is not a virtual class. FitObject is a pure virtual class and CSensor is the class derived of. WorldCoord is a class which is inside a DLL.
WorldCoord is a virtual class, because it has a virtual member function.
Look at the destructor.
virtual ~WorldCoord();
That's a virtual destructor. A class with any virtual function becomes a virtual class.
@Axter,
I made WorldCoord now non virtual by removing the empty destructor.
Now &wcAct is inside the function the first data element, not the vftable anymore. This means to me, that the var is put by value onto the stack and is interpreted as address by the function. So I should blame the calling function putting the value (from assembly it seems to be a temporary copy of it) and not address onto the stack. But why does it fail for a const & and not for a simple ref? Do I need some more operators/functions for the class WorldCoord?
void CSensor::ToWorldFit(WorldC
{
//* correct version for fitting measured points on sensor.
wcPos = m_wcOffset - wcPos;
wcPos.Rotate (-m_dPhi); // sensor rotation only depends on internal angle
wcPos.m_dU += wcAct.m_dU;
wcPos.m_dV += wcAct.m_dV;
//*/
return;
}
and the calling function
Double_t TSpecialFit::Chisquare(Int
{
if (fNpoints <= 0)
return 0.;
Double_t chisq = 0;
Int_t n1 = fNpoints / fNrefs + 1;
Int_t i,j,k;
Double_t tx1, ty1;//, tx2, ty2;
Double_t phik;
WorldCoord wcPos, wcPos1, wcPos2, wcAct; // current pos and camera pos
MotorCoord mcPos;
for (k=0;k<fNpoints;++k) {
i = k % fNrefs;
j = k / fNrefs;
phik = fPhi[k] / 1000 * deg2rad;
// Step 1
wcPos.m_dU = fX2[k];
wcPos.m_dV = fY2[k];
wcPos.m_dW = 0;
wcPos1.m_dU = par[0];
wcPos1.m_dV = par[1];
fpFitObj->SetOffset (wcPos1);
wcPos1.m_dU = par[3];
wcPos1.m_dV = par[4];
fpFitObj->SetCamPos (wcPos1);
switch (fiType) {
case 3: // sensor
case 5: // mask
// since ToWorld with wcAct needs to be used wcAct is set to Cam1Pos
wcAct.m_dU = par[3];
wcAct.m_dV = par[4];
wcAct.m_dW = 0;
break;
default:
wcAct.m_dU = 0;
wcAct.m_dV = 0;
wcAct.m_dW = 0;
break;
}
fpFitObj->SetPhi (par[2]);
fpFitObj->ToWorldFit (wcPos, wcAct, phik); // wcAct = cam1pos // for CChip +phik is correct solution!
if ((fiType != 3) && (fiType != 5)) {
wcPos += wcPos1; // subtract position of camera 2 relative to rotation center at 0/0
}
mcPos.ToMotor (wcPos); //, tCal);
tx1 = fX1[k] - mcPos.m_lX;
ty1 = fY1[k] - mcPos.m_lY;
chisq += tx1*tx1+ty1*ty1;
}
return chisq;
}
It looks like the TSpecialFit::Chisquare function is using the wrong variable.
It's using a variable fNpoints instead of input variable npar.
npar is not used in the function at all.
par is being indexed, but there's nothing to verify that the constant index's are not going pass the boundry of the par array.
@Axter
The class TSpecialFit is part of a DLL handling an interface to ROOT http://root.cern.ch. I just modified an example, but your right I don't check whether the index for par is in range. On the other hand the number or parameters are set in another member function of TSpecialFit and all are defined by myself. So I know what I am doing here (and hope its correct). npar is the number of free parameters and therefor not helpful to check the index. For the chisquare I need all parameters even the fixed ones. fNpoints is another member variable with the number of points in fX1, fX2, fY1, and fY2 indexed by variable k.
What makes me think that ist really the call to ToWorldFit is that using
const WorldCoord wcAct
the program does its work.
When using
const WorldCoord& wcAct
the address of wcAct is the first member in wcAct and not its memory location and the difference between ESP and ESI in __chkesp is sizeof (WorldCoord) - sizeof (WorlCoord*) which means to me a value has been put on the stack and the function is looking for the address only.
Double_t is a 8 byte float on all compilers known to ROOT. For VC++ 6.0 its equal to a plain double.
@all
Thanks for all your suggestions. I will do the suggested tests later and report if this helps (alignment?).
It took me a while to do some testing with partly reduced code and simple examples. My finding is now:
the call
fpFitObj->ToWorldFit (wcPos, wcAct, phik);
defined as
virtual void ToWorldFit(WorldCoord& wcPos, const WorldCoord& wcAct, const double dPhi);
gets not properly compiled it seems. I had a look at the assembly of it in the debugger. The double dPhi is put on the stack, then a copy of wcAct is taken and put on the stack by value followed by the address of wcPos. The called function finds now
- the address of wcPos (4 bytes) OK
- wcAct as 24 bytes of 0; should be address
- and the value of dPhi (8 bytes). OK
but it interpretes the first 4 bytes as the address of wcPos; OK.
the next 4 bytes as the address of wcAct; very bad = 0!
and the next 8 bytes as the value of phik; here 0 instead of -0.17!
Can any #pragma in headers change this behaviour?
Any suggestions for compiler options to look at?
I've compared all under C/C++ and Link and they agree.
Meanwhile the bug is found: The DLL code was linking to an include file of an old version of the main application. The main application meanwhile has evolved. The DLL was using the old function declaration and for the main app I changed it. And only if either function matched the executable ran.
No chance for experts to find the bug, since this part I omitted the part where that header was included.
Business Accounts
Answer for Membership
by: AlexFMPosted on 2003-10-22 at 00:35:37ID: 9596985
Can you show some code?