Click to See Complete Forum and Search --> : Compiler Warning C4373 about virtual methods


George2
February 25th, 2008, 07:36 AM
Hello everyone,


The following code will result in C4373 warning message. In MSDN,

http://msdn2.microsoft.com/en-us/library/bb384874.aspx

I do not quite understand the following statement,

1. What means "bind"? Putting function pointer into the vtable of the related class?

2. const is ignored in derived class?

--------------------
This means the compiler must bind a function reference to the method in either the base or derived class.

Versions of the compiler prior to Visual C++ 2008 bind the function to the method in the base class, then issue a warning message. Subsequent versions of the compiler ignore the const or volatile qualifier, bind the function to the method in the derived class, then issue warning C4373. This latter behavior complies with the C++ standard.
--------------------


class Base {
public:
virtual int goo (const int input) {return 200;}
};

class Derived : public Base {
public:
virtual int goo (int input) {return 200;} // change const property of input parameter
};

int main()
{
Derived d;
const int a = 1000;
d.goo (a); // pass const to non-const

return 0;
}


Compile warning message,

1>d:\visual studio 2008\projects\test_overriding1\test_overriding1\main.cpp(8) : warning C4373: 'Derived::goo': virtual function overrides 'Base::goo', previous versions of the compiler did not override when parameters only differed by const/volatile qualifiers
1> d:\visual studio 2008\projects\test_overriding1\test_overriding1\main.cpp(3) : see declaration of 'Base::goo'


regards,
George

angelorohit
February 25th, 2008, 09:34 AM
Hey George,

1. Yes, in this context, "binding to a class" means associating the vTable pointer to the corresponding function in that class.
2. Are you asking if the constness of a is lost in Derived::goo()? Yes, that is correct. However, since you are passing a by value (you can't pass a by non-const reference), whatever changes you make to the parameter inside the function will not affect a. Incidentally, MinGW 3.7 does not give any warning and successfully binds the function to the derived class method. Wonder why Microsoft took so long to realise this?

Lindley
February 25th, 2008, 09:56 AM
On a related note, I just encountered the old "class has virtual functions but non-virtual destructor" warning.

I know I've encountered and dealt with this before, but the details are slipping my mind at the moment.

The base class is pure-virtual, existing only so that I can use common accessor functions on several derived classes. No destructors are explicitly defined for any of them; they contain only POD and some STL containers (which have their own destructors), so I assumed the default destructor would be good enough.

What do I need to do to make the warning go away? (Besides just disabling it, of course.)

angelorohit
February 25th, 2008, 10:17 AM
Hey Lindley,
Could you post some working code illustrating the problem?

Lindley
February 25th, 2008, 10:25 AM
Not easily. However, I can post simplified class declarations. Since this isn't exactly an obscure error, that should be enough to tell me what I'm doing wrong. Google turned up a number of hits on the message, but none of the explanations were completely clear.


class GraphPart
{
public:
virtual void setField(std::string fieldname, std::string value)=0;
virtual bool cmpField(std::string fieldname, std::string value) const=0;
virtual const char* getField(std::string fieldname) const=0;
};

class GraphNode: public GraphPart
{
public:
// data is a mix of non-pointer primitives and STL containers, nothing else

void setField(std::string fieldname, std::string value);
bool cmpField(std::string fieldname, std::string value) const;
const char* getField(std::string fieldname) const;
};

class GraphEdge: public GraphPart
{
public:
// data is non-pointer primitives

void setField(std::string fieldname, std::string value);
bool cmpField(std::string fieldname, std::string value) const;
const char* getField(std::string fieldname) const;
};



Before anyone mentions it, the reasoning for not using const string references in the parameters is so that const char*-type strings, including literals, may be passed.

laserlight
February 25th, 2008, 10:30 AM
Before anyone mentions it, the reasoning for not using const string references in the parameters is so that const char*-type strings, including literals, may be passed.
Eh, but temporaries and literals can be bound to const references.

EDIT:
The warning is just that you should declare the base class destructor virtual so as to avoid undefined behaviour if an object of a derived class is deleted through a pointer to the base class.

Lindley
February 25th, 2008, 10:48 AM
I had previously tried that (the const reference thing), and got errors. Just did again and it worked. Oh well, I must have screwed something up last time.

Likewise, when I tried adding a pure virtual destructor to the base class I got undefined symbol messages....turns out that even pure virtual classes need actual destructor definitions (!?) in order to compile, even when they're virtual.

laserlight
February 25th, 2008, 11:01 AM
Likewise, when I tried adding a pure virtual destructor to the base class I got undefined symbol messages....turns out that even pure virtual classes need actual destructor definitions (!?) in order to compile, even when they're virtual.
Yes, that is true. It sounds like you just ran into a stroke of bad luck or something, heheh.

angelorohit
February 25th, 2008, 11:07 AM
On a related note, I just encountered the old "class has virtual functions but non-virtual destructor" warning.

I know I've encountered and dealt with this before, but the details are slipping my mind at the moment.

The base class is pure-virtual, existing only so that I can use common accessor functions on several derived classes. No destructors are explicitly defined for any of them; they contain only POD and some STL containers (which have their own destructors), so I assumed the default destructor would be good enough.

What do I need to do to make the warning go away? (Besides just disabling it, of course.)I know that you need to make the destructor in the base class virtual. Unfortunately, I am not able to reproduce this warning with my VS 2005 compiler. What compiler are you using Lindley?


Likewise, when I tried adding a pure virtual destructor to the base class I got undefined symbol messages....turns out that even pure virtual classes need actual destructor definitions (!?) in order to compile, even when they're virtual.

Section 12.4 in the standard:
A destructor can be declared virtual (10.3) or pure virtual (10.4); if any objects of that class or any derived class are created in the program, the destructor shall be defined.

Lindley
February 25th, 2008, 11:13 AM
I know that you need to make the destructor in the base class virtual. Unfortunately, I am not able to reproduce this warning with my VS 2005 compiler. What compiler are you using Lindley?


Neither am I, even on -W4, and that was part of the problem. This came off a list of warnings generated on Linux by g++ on my code that was sent to me. I write all my code to be cross-platform.


Section 12.4 in the standard:
A destructor can be declared virtual (10.3) or pure virtual (10.4); if any objects of that class or any derived class are created in the program, the destructor shall be defined.

If I'm reading that right----mentally substituting "must" for "shall" at the end there----that seems arbitrary, but at least it's something to work from.

TheCPUWizard
February 25th, 2008, 11:33 AM
1) EVERY class must have a destructor implementation. It can be the "generated" destructor, or an explicitly written destructor. This may be optimized out of existance, but must initialy exist.

2) When you declare any method (including the destructor) it prevents the creation of a default implementation

3) The destructor of a base class (even if it has no members) MUST be virtual in order to funcion properly, if any of the derived classes have any data members. Since this can NOT be detected by the compiler by looking at only the base class, it generates a warning:

Consider:

class Base
{
~Base(); // NOT virtual...
}

class Derived
{
private SomeThing s;
}


B *test = new Derived();
delete test;

There is no way for the delete to invoke the (automatic) destricutor of class Derived (a virtual destructor on Base is required). Therefore D::s will never be properly destructed.

Clear?

}

Lindley
February 25th, 2008, 11:35 AM
Makes sense. The confusion was mainly on why a pure virtual base class would need a destructor definition, as opposed to merely a declaration that it was virtual.

George2
February 26th, 2008, 01:12 AM
Hi Lindley,


I have tried to compile your code in Visual Studio 2008, no compile warning/errors.

Do you have any comments?

Why your code have something to do with my original question?

Not easily. However, I can post simplified class declarations. Since this isn't exactly an obscure error, that should be enough to tell me what I'm doing wrong. Google turned up a number of hits on the message, but none of the explanations were completely clear.


class GraphPart
{
public:
virtual void setField(std::string fieldname, std::string value)=0;
virtual bool cmpField(std::string fieldname, std::string value) const=0;
virtual const char* getField(std::string fieldname) const=0;
};

class GraphNode: public GraphPart
{
public:
// data is a mix of non-pointer primitives and STL containers, nothing else

void setField(std::string fieldname, std::string value);
bool cmpField(std::string fieldname, std::string value) const;
const char* getField(std::string fieldname) const;
};

class GraphEdge: public GraphPart
{
public:
// data is non-pointer primitives

void setField(std::string fieldname, std::string value);
bool cmpField(std::string fieldname, std::string value) const;
const char* getField(std::string fieldname) const;
};



Before anyone mentions it, the reasoning for not using const string references in the parameters is so that const char*-type strings, including literals, may be passed.


regards,
George

George2
February 26th, 2008, 01:19 AM
Hi angelorohit,


I am confused what do you mean "(you can't pass a by non-const reference)".

I have shown you the code below, we can pass non-const reference to method goo. Any comments?


class Base {
public:
virtual int goo (const int input) {return 200;}
};

class Derived : public Base {
public:
virtual int goo (int input) {return 200;} // change const property of input parameter
};

int main()
{
Derived d;
int a = 100;
int& ri = a;
d.goo (ri); // pass const to non-const

return 0;
}


Hey George,

1. Yes, in this context, "binding to a class" means associating the vTable pointer to the corresponding function in that class.
2. Are you asking if the constness of a is lost in Derived::goo()? Yes, that is correct. However, since you are passing a by value (you can't pass a by non-const reference), whatever changes you make to the parameter inside the function will not affect a. Incidentally, MinGW 3.7 does not give any warning and successfully binds the function to the derived class method. Wonder why Microsoft took so long to realise this?


regards,
George

George2
February 26th, 2008, 01:23 AM
Thanks Lindley,


What does your term "common accessor functions" mean? I searched for wikipedia and Google, can not find the definition. :-)

On a related note, I just encountered the old "class has virtual functions but non-virtual destructor" warning.

I know I've encountered and dealt with this before, but the details are slipping my mind at the moment.

The base class is pure-virtual, existing only so that I can use common accessor functions on several derived classes. No destructors are explicitly defined for any of them; they contain only POD and some STL containers (which have their own destructors), so I assumed the default destructor would be good enough.

What do I need to do to make the warning go away? (Besides just disabling it, of course.)


regards,
George

laserlight
February 26th, 2008, 01:33 AM
I am confused what do you mean "(you can't pass a by non-const reference)".

I have shown you the code below, we can pass non-const reference to method goo. Any comments?
In your original code a was declared const.

George2
February 26th, 2008, 01:38 AM
Thanks Lindley,


1.


#include <string>

using namespace std;

void foo1 (const string& abc)
{
return;
}

string foo2()
{
return "temp string";
}

void goo()
{
// passing literal to const string reference
foo1 ("MyAbc");
// passing temporary to const string reference
foo1 (foo2());

return;
}


I had previously tried that (the const reference thing), and got errors. Just did again and it worked. Oh well, I must have screwed something up last time.

laserlight is correct, and I have written code to prove. Compile ok in Visual Studio 2008.

2.

Likewise, when I tried adding a pure virtual destructor to the base class I got undefined symbol messages....turns out that even pure virtual classes need actual destructor definitions (!?) in order to compile, even when they're virtual.

Can you show us what is the purpose to define a pure virtual destructor please?


regards,
George

George2
February 26th, 2008, 01:42 AM
Hi laserlight,


Using pure virtual destructor in base class does not have any issues. Here is my code in Visual Studio 2008, compile ok. :-)

Anyway, could you share your experience about what is the function of a pure-virtual destructor and in what situations do we need please?


#include <string>
#include <iostream>

using namespace std;

class GraphPart
{
public:
virtual void setField(std::string fieldname, std::string value)=0;
virtual bool cmpField(std::string fieldname, std::string value) const=0;
virtual const char* getField(std::string fieldname) const=0;
virtual ~GraphPart() = 0;
};

class GraphNode: public GraphPart
{
public:
// data is a mix of non-pointer primitives and STL containers, nothing else

void setField(std::string fieldname, std::string value);
bool cmpField(std::string fieldname, std::string value) const;
const char* getField(std::string fieldname) const;
};

class GraphEdge: public GraphPart
{
public:
// data is non-pointer primitives

void setField(std::string fieldname, std::string value);
bool cmpField(std::string fieldname, std::string value) const;
const char* getField(std::string fieldname) const;
};



Yes, that is true. It sounds like you just ran into a stroke of bad luck or something, heheh.


regards,
George

laserlight
February 26th, 2008, 01:43 AM
Can you show us what is the purpose to define a pure virtual destructor please?
I believe this has come up several times before on this forum. A pure virtual destructor may be used when you want the class to be an abstract base class, but none of the member functions are suitable candidates to be declared pure virtual. However, the base class still needs an implementation for the destructor since it will be invoked from the derived class' destructor. Lindley's problem was this lack of an implementation for the pure virtual destructor.

George2
February 26th, 2008, 01:45 AM
Thanks angelorohit,


I do not think at least Visual Studio 2008 follows this rule. You can refer to my post #18 and see even if the derived class is defined, the destructor of base class could still be pure virtual.

Any comments?


Section 12.4 in the standard:
A destructor can be declared virtual (10.3) or pure virtual (10.4); if any objects of that class or any derived class are created in the program, the destructor shall be defined.


regards,
George

laserlight
February 26th, 2008, 01:47 AM
I do not think at least Visual Studio 2008 follows this rule. You can refer to my post #18 and see even if the derived class is defined, the destructor of base class could still be pure virtual.

Any comments?
You're reading the rule wrongly.

George2
February 26th, 2008, 01:50 AM
Hi TheCPUWizard,


Your code shows why needs to define it virtual, but not why needs to define it pure virtual...

Any comments?

1) EVERY class must have a destructor implementation. It can be the "generated" destructor, or an explicitly written destructor. This may be optimized out of existance, but must initialy exist.

2) When you declare any method (including the destructor) it prevents the creation of a default implementation

3) The destructor of a base class (even if it has no members) MUST be virtual in order to funcion properly, if any of the derived classes have any data members. Since this can NOT be detected by the compiler by looking at only the base class, it generates a warning:

Consider:

class Base
{
~Base(); // NOT virtual...
}

class Derived
{
private SomeThing s;
}


B *test = new Derived();
delete test;

There is no way for the delete to invoke the (automatic) destricutor of class Derived (a virtual destructor on Base is required). Therefore D::s will never be properly destructed.

Clear?

}


regards,
George

George2
February 26th, 2008, 01:54 AM
Thanks laserlight,


You mean variable a is const or the input parameter type of goo in derived class is const?

In your original code a was declared const.


regards,
George

laserlight
February 26th, 2008, 02:02 AM
You mean variable a is const or the input parameter type of goo in derived class is const?
There is only one variable named a in your original code, and it is a const int. The variable named a in your new example is a non-const int, so it can be passed by non-const reference.

angelorohit wrote: "since you are passing a by value (you can't pass a by non-const reference)". In other words, you are passing a by value, and that is fine.

However, if you try to pass a by non-const reference, then it will not work. To pass a by non-const reference, you have to change the input parameter of goo() to a non-const reference. Then you pass in a, which is a const int.

George2
February 26th, 2008, 02:10 AM
Hi laserlight,


I read your comments a couple of time, but confused.

1. We need pure virtual function when we are implementing a pure virtual class but none of other functions are appropriate to define as pure virtual;

Seems it is ok and reasonable to define a destructor pure virtual.

2. "However, the base class still needs an implementation for the destructor since it will be invoked from the derived class' destructor."

Seems not ok to define a destructor pure virtual.

What is the truth? Any comments?

I believe this has come up several times before on this forum. A pure virtual destructor may be used when you want the class to be an abstract base class, but none of the member functions are suitable candidates to be declared pure virtual. However, the base class still needs an implementation for the destructor since it will be invoked from the derived class' destructor. Lindley's problem was this lack of an implementation for the pure virtual destructor.


regards,
George

laserlight
February 26th, 2008, 02:13 AM
2. "However, the base class still needs an implementation for the destructor since it will be invoked from the derived class' destructor."

Seems not ok to define a destructor pure virtual.

What is the truth? Any comments?
Basically:
class X
{
public:
virtual ~X() = 0; // pure virtual destructor
};

X::~X() {} // implementation of the pure virtual destructor

George2
February 26th, 2008, 02:15 AM
No laserlight,


For your below quoted comments, we can pass a non-const reference to goo without changing the original code, here is my code. Any comments?

i.e. we can pass non-const reference type to non-const value type.


class Base {
public:
virtual int goo (const int input) {return 200;}
};

class Derived : public Base {
public:
virtual int goo (int input) {return 200;} // change const property of input parameter
};

int main()
{
Derived d;
int a = 100;
int& ra = a;
d.goo (ra); // pass non-const reference type to non-const value type

return 0;
}



However, if you try to pass a by non-const reference, then it will not work. To pass a by non-const reference, you have to change the input parameter of goo() to a non-const reference. Then you pass in a, which is a const int.


regards,
George

George2
February 26th, 2008, 02:18 AM
Thanks laserlight,


1. Pure virtual function can have an implementation? e.g. your designed destructor?

2. In your code, seem two purposes are achieved

A. base class has pure virtual function (in your sample code, the destructor), which can not be created directly;
B. base class's destructor has implementation body, which could be invoked from derived class's destructor.

Right?

Basically:
class X
{
public:
virtual ~X() = 0; // pure virtual destructor
};

X::~X() {} // implementation of the pure virtual destructor


regards,
George

laserlight
February 26th, 2008, 02:20 AM
For your below quoted comments, we can pass a non-const reference to goo without changing the original code, here is my code. Any comments?
Your code does not really illustrate the point that angelorohit was trying to make. In fact, angelorohit's point was just a passing comment. Furthermore, your code is fundamentally different from your original.

If you want something closer to the original, try compiling:
class Base {
public:
virtual int goo (const int input) {return 200;}
};

class Derived : public Base {
public:
virtual int goo (int input) {return 200;} // change const property of input parameter
};

int main()
{
Derived d;
const int a = 100;
int& ra = a;
d.goo (ra); // pass non-const reference type to non-const value type

return 0;
}
Notice that a is now a const int.


For your below quoted comments, we can pass a non-const reference to goo without changing the original code, here is my code. Any comments?
Your code does not really illustrate the point that angelorohit was trying to make. In fact, angelorohit's point was just a passing comment. Furthermore, your code is fundamentally different from your original.

If you want something closer to the original, try compiling:
class Base {
public:
virtual int goo (const int input) {return 200;}
};

class Derived : public Base {
public:
virtual int goo (int input) {return 200;} // change const property of input parameter
};

int main()
{
Derived d;
const int a = 100;
int& ra = a;
d.goo (ra); // pass non-const reference type to non-const value type

return 0;
}
Notice that a is now a const int.

1. Pure virtual function can have an implementation? e.g. your designed destructor?
Only in this case where a pure virtual destructor is involved, otherwise an implementation for a pure virtual function does not make sense since it should then just be a virtual function.

2. In your code, seem two purposes are achieved

A. base class has pure virtual function (in your sample code, the destructor), which can not be created directly;
B. base class's destructor has implementation body, which could be invoked from derived class's destructor.
Yes.

George2
February 26th, 2008, 02:21 AM
Hi laserlight,


I read again. This is the rule,

--------------------
A destructor can be declared virtual (10.3) or pure virtual (10.4); if any objects of that class or any derived class are created in the program, the destructor shall be defined.
--------------------

My code is posted in #18. It breaks this rule.

Anything wrong? Appreciated if you could point out.

You're reading the rule wrongly.


regards,
George

laserlight
February 26th, 2008, 02:24 AM
My code is posted in #18. It breaks this rule.

Anything wrong? Appreciated if you could point out.
Oh, I did not read your code carefully.

Of course something is wrong. Try creating a GraphNode object.

George2
February 26th, 2008, 02:30 AM
Thanks laserlight,


1.

Your code does not really illustrate the point that angelorohit was trying to make. In fact, angelorohit's point was just a passing comment. Furthermore, your code is fundamentally different from your original.

If you want something closer to the original, try compiling:
class Base {
public:
virtual int goo (const int input) {return 200;}
};

class Derived : public Base {
public:
virtual int goo (int input) {return 200;} // change const property of input parameter
};

int main()
{
Derived d;
const int a = 100;
int& ra = a;
d.goo (ra); // pass non-const reference type to non-const value type

return 0;
}
Notice that a is now a const int.



Your code does not really illustrate the point that angelorohit was trying to make. In fact, angelorohit's point was just a passing comment. Furthermore, your code is fundamentally different from your original.

I have verified the code you posted. Here is the compile error.

error C2440: 'initializing' : cannot convert from 'const int' to 'int &'

So, I think it breaks the C++ rule that can not bind non-const reference to a const value variable, right?

int& ra = a;

But, I do not know does this rule have anything to do with passing parameter to foo? You can see the above line compile fails in main, before passing parameter to function goo.

2.

Only in this case where a pure virtual destructor is involved, otherwise an implementation for a pure virtual function does not make sense since it should then just be a virtual function.

"in this case" you mean when base class destructor is invoked from derived class?


regards,
George

George2
February 26th, 2008, 02:36 AM
Thanks laserlight,


My bad. I have tried. Compile ok but link error. Here is the error information and related code.

So the fix is to implement the destructor in base class GraphPart, right? My understanding and code are correct?

1>main.obj : error LNK2019: unresolved external symbol "public: virtual __thiscall GraphPart::~GraphPart(void)" (??1GraphPart@@UAE@XZ) referenced in function "public: virtual __thiscall GraphNode::~GraphNode(void)" (??1GraphNode@@UAE@XZ)


#include <string>
#include <iostream>

using namespace std;

class GraphPart
{
public:
virtual void setField(std::string fieldname, std::string value)=0;
virtual bool cmpField(std::string fieldname, std::string value) const=0;
virtual const char* getField(std::string fieldname) const=0;
virtual ~GraphPart() = 0;
};

class GraphNode: public GraphPart
{
public:
// data is a mix of non-pointer primitives and STL containers, nothing else

void setField(std::string fieldname, std::string value) {};
bool cmpField(std::string fieldname, std::string value) const {return true;};
const char* getField(std::string fieldname) const {return NULL;};
};

class GraphEdge: public GraphPart
{
public:
// data is non-pointer primitives

void setField(std::string fieldname, std::string value) {};
bool cmpField(std::string fieldname, std::string value) const {return true;};
const char* getField(std::string fieldname) const {return NULL;};
};

int main()
{
GraphNode gn;

return 0;
}


Oh, I did not read your code carefully.

Of course something is wrong. Try creating a GraphNode object.


regards,
George

laserlight
February 26th, 2008, 02:41 AM
But, I do not know does this rule have anything to do with passing parameter to foo? You can see the above line compile fails in main, before passing parameter to function goo.
angelorohit's main point is that to the caller:
int goo(const int input);
is no different from:
int goo(int input);

There const keyword only makes a difference for:
int goo(const int& input);
versus:
int goo(int& input);

angelorohit's side point, which you seem to be having so much trouble with, is that you cannot write:
int foo(int& input)
{
return input;
}

int main()
{
const int a = 0;
foo(a);
}

If you find it easier to understand, just ignore angelorohit's side point. It has nothing to do with your actual code, but is an observation of what you did not, and cannot, do.

"in this case" you mean when base class destructor is invoked from derived class?
Yes. Note that there is no actual override as is normal for virtual functions. Rather, the derived class destructor invokes the base class destructor, as per the normal routine for object destruction.

George2
February 26th, 2008, 03:06 AM
Thanks laserlight,


1.

Your below comments about reference and value are great! I have made exercise.

1.1 For the value, no differences between const and non-const is because there is a copy made on the input parameter, not caring the original one and operating on the original one in the function;

1.2 For the reference, since function will operate on the original one, so it matters about const property -- we can make the variable more strict, but not more loose;

Any code and understanding are correct? :-)


int goo1 (const int input)
{
return 1;
}

int goo2 (int input)
{
return 2;
}

int goo3 (const int& input)
{
return 3;
}

int goo4 (int& input)
{
return 4;
}

void gooTest()
{
const int a = 100;
goo1(a); // compile ok
goo2(a); // compile ok

goo3 (a); // compile ok
goo4 (a); // error C2664: 'goo4' : cannot convert parameter 1 from 'const int' to 'int &'

return;
}


2.

about your comments,

"Note that there is no actual override as is normal for virtual functions.", I am interested what do you mean no actual overrides? Could you provide more information please?

In my mind, when you create an instance of derived object instance, and assign it to a base class pointer, then call the destructor, then the derived class' destructor is called, so it has overridding effect. What is your point?

angelorohit's main point is that to the caller:
int goo(const int input);
is no different from:
int goo(int input);

There const keyword only makes a difference for:
int goo(const int& input);
versus:
int goo(int& input);

angelorohit's side point, which you seem to be having so much trouble with, is that you cannot write:
int foo(int& input)
{
return input;
}

int main()
{
const int a = 0;
foo(a);
}

If you find it easier to understand, just ignore angelorohit's side point. It has nothing to do with your actual code, but is an observation of what you did not, and cannot, do.


Yes. Note that there is no actual override as is normal for virtual functions. Rather, the derived class destructor invokes the base class destructor, as per the normal routine for object destruction.


regards,
George

angelorohit
February 26th, 2008, 04:19 AM
Thanks laserlight for clearing George2's doubts from my end. For some reason, I wasn't getting the notification e-mail from this thread and I overslept today. :D

George2
February 26th, 2008, 04:31 AM
Thanks to laserlight the same, I feel I learned a lot from this thread. :-)


Thanks laserlight for clearing George2's doubts from my end. For some reason, I wasn't getting the notification e-mail from this thread and I overslept today. :D


regards,
George

laserlight
February 26th, 2008, 05:31 AM
In my mind, when you create an instance of derived object instance, and assign it to a base class pointer, then call the destructor, then the derived class' destructor is called, so it has overridding effect.
Yes, you are correct. The derived class destructor does override the base class destructor if the latter is declared virtual.

TheCPUWizard
February 26th, 2008, 06:32 AM
i.e. we can pass non-const reference type to non-const value type.


class Base {
public:
virtual int goo (const int input) {return 200;}
};

class Derived : public Base {
public:
virtual int goo (int input) {return 200;} // change const property of input parameter
};

int main()
{
Derived d;
int a = 100;
int& ra = a;
d.goo (ra); // pass non-const reference type to non-const value type

return 0;
}



WRONG!!!!

You are passing an integer by value. What is passed is totally controlled by the method declaration. The parameter has nothing to do with it (diectly).

Your variable "ra" is a reference to your variable "a" which contains the value 100. So you are passing a copy of the value 100 to the method.

If you want to pass a const reference:

virtual int goo (const int &input) {...}

If you want to pass a non-const reference:

virtual int goo (int& input) {...}


Once again your utter lack of understanding of the most basic trminology and functionallity is causing you to make fundamental mistakes. Why are you so insistant on not getting a good book, and actually trying to learn the basics??????

George2
February 26th, 2008, 08:27 PM
Sorry TheCPUWizard,


It is my carelessness in yesterday's flood of discussion. It is basic things and surely I understand. :-)

WRONG!!!!

You are passing an integer by value. What is passed is totally controlled by the method declaration. The parameter has nothing to do with it (diectly).

Your variable "ra" is a reference to your variable "a" which contains the value 100. So you are passing a copy of the value 100 to the method.

If you want to pass a const reference:

virtual int goo (const int &input) {...}

If you want to pass a non-const reference:

virtual int goo (int& input) {...}


Once again your utter lack of understanding of the most basic trminology and functionallity is causing you to make fundamental mistakes. Why are you so insistant on not getting a good book, and actually trying to learn the basics??????


regards,
George

George2
February 26th, 2008, 08:31 PM
Hi laserlight,


Sorry I do not agree with you. Even if we define the base class's destructor as pure virtual (not virtual as you mentioned), there is still expected virtual function behavior. Here is the code and output, any comments?

I am confused what do you mean "Note that there is no actual override as is normal for virtual functions."? Any special behavior when we define base class's destructor as pure virtual?


#include <string>
#include <iostream>

using namespace std;

class GraphPart
{
public:
virtual void setField(std::string fieldname, std::string value) {};
virtual bool cmpField(std::string fieldname, std::string value) const {return true;}
virtual const char* getField(std::string fieldname) const {return NULL;}
virtual ~GraphPart() = 0;
};

/*
If remove the following destructor implementation, there will be link error, about unresolved reference to destructor of class GraphPart
*/
GraphPart::~GraphPart()
{
cout << "GraphPart " << endl;
}

class GraphNode: public GraphPart
{
public:
// data is a mix of non-pointer primitives and STL containers, nothing else

void setField(std::string fieldname, std::string value) {};
bool cmpField(std::string fieldname, std::string value) const {return true;}
const char* getField(std::string fieldname) const {return NULL;}
~GraphNode()
{
cout << "GraphNode " << endl;
}
};

class GraphEdge: public GraphPart
{
public:
// data is non-pointer primitives

void setField(std::string fieldname, std::string value) {};
bool cmpField(std::string fieldname, std::string value) const {return true;}
const char* getField(std::string fieldname) const {return NULL;}
};

int main()
{
GraphNode gn;
GraphPart* pgp = &gn;

return 0;
}


output:

GraphNode
GraphPart

Yes, you are correct. The derived class destructor does override the base class destructor if the latter is declared virtual.


regards,
George

laserlight
February 26th, 2008, 11:12 PM
Sorry I do not agree with you. Even if we define the base class's destructor as pure virtual (not virtual as you mentioned), there is still expected virtual function behavior. Here is the code and output, any comments?

I am confused what do you mean "Note that there is no actual override as is normal for virtual functions."? Any special behavior when we define base class's destructor as pure virtual?
As I noted, your interpretation that the derived class destructor overrides the base class destructor is correct (I double checked the standard). What I should have highlighted was that the base class destructor is not inherited, so the override mechanism is not quite the same as normal since the derived class destructor still invokes the base class destructor.

In this respect, it does not matter if the base class destructor is defined as pure virtual or just virtual: the override happens either way, and either way the derived class destructor invokes the base class destructor.

George2
February 27th, 2008, 02:16 AM
Thanks laserlight,


I think you mean,

1. in normal overriding, derived class hides the methods of base class, so when we invoke the methods on derived class, just the method in derived class is invoked;

2. in destructor overridding, when we call destructor of derived class, the destructor method in base class is not hidden, and still invoked by derived class' destructor?

Is that what you mean?

As I noted, your interpretation that the derived class destructor overrides the base class destructor is correct (I double checked the standard). What I should have highlighted was that the base class destructor is not inherited, so the override mechanism is not quite the same as normal since the derived class destructor still invokes the base class destructor.

In this respect, it does not matter if the base class destructor is defined as pure virtual or just virtual: the override happens either way, and either way the derived class destructor invokes the base class destructor.


regards,
George

laserlight
February 27th, 2008, 02:25 AM
Is that what you mean?
I am not sure if hidden is the right word, but yes, that is what I mean.

George2
February 27th, 2008, 02:55 AM
Thanks laserlight,


I am not sure if hidden is the right word, but yes, that is what I mean.

My question is answered. Thanks for your long help.


regards,
George