Click to See Complete Forum and Search --> : once virtual, always virtual?
spitzerg
February 22nd, 2006, 08:26 PM
So, I was recently reading mozilla's portability FAQ and item #25 surprised me and I was wondering if anyone could lend some insight to what I have always thought in the past.
http://www.mozilla.org/hacking/portable-cpp.html#virtual_on_subclasses
According to them once something is virtual it will always be which means to me it can therefore not be inlined and will always require a vtable. However, I always thought that in the following example the call to b.foo() would be inlined (and maybe even a->foo() on really tricky optimizing compilers though certainly not to be expected in more complex cases).
class A
{
public:
virtual void foo() { cout << "A" << endl; }
};
class B
{
public:
void foo() { cout << "B" << endl; }
};
int main()
{
B b;
b.foo();
A* a = &b;
a->foo();
return 0;
}
I do believe them that this might not be entirely portable though I'm not too concerned with that as we only need to support a small number of compilers, but I would like to know if there is a reason that my belief that b.foo() would be inlined is wrong and if so why that might be.
Thanks
Kheun
February 22nd, 2006, 08:39 PM
Shouldn't you be inheriting class B from class A?
class A
{
public:
virtual void foo() { cout << "A" << endl; }
};
class B: public A
{
public:
void foo() { cout << "B" << endl; }
};
int main()
{
B b;
b.foo();
A* a = &b;
a->foo();
return 0;
}
Anyway, the b::foo couldn't be inlined because A::foo is being declared as virtual. As a result, the vtable will be used whenever foo is being invoked.
spitzerg
February 22nd, 2006, 08:47 PM
Yeah, sorry, I meant to inherit B from A.
So I guess the answer is though that things will always be virtual which is kind of disappointing. I always thought taking out the virtual would effectively end the vtable and allow things to be optimized when enought type information was available.
Thanks for the answer.
Hobson
February 23rd, 2006, 01:42 AM
In your example when you are calling b.foo() no virtual mechanism is used, because b is an object, not a reference nor pointer. Type of b is known and there is no need to use vtable, so call could be inlined.
Regards,
Hob
exterminator
February 23rd, 2006, 05:15 AM
So I guess the answer is though that things will always be virtual which is kind of disappointing. I always thought taking out the virtual would effectively end the vtable and allow things to be optimized when enought type information was available.Nopes.. the virtual keyword in the over-ride is redundant (but still has the virtual effect as declared in the base class) but it is always better to keep it... to make it informative. Regards.
Graham
February 23rd, 2006, 05:35 AM
Nopes.. the virtual keyword in the over-ride is redundant (but still has the virtual effect as declared in the base class) but it is always better to keep it... to make it informative. Regards.
My preferred style is to only use virtual when the function is first introduced, and to clearly mark out the overrides in derived classes (but without the virtual):
class foo1
{
public:
virtual int foo1m1(int) = 0;
virtual void foo2m2() = 0;
};
class foo2
{
public:
virtual int foo2m1() = 0;
};
class bar : public foo1, public foo2
{
public:
// bar's own functions
public:
//! @name From foo1
//@{
int foo1m1(int);
void foo1m2();
//@}
public:
//! @name From foo2
//@{
int foo2m1();
//@}
};
Note the redundant use of the access specifier - I use it to clearly mark different conceptual sections of the class interface (I'll also use separate privates for private functions and private data). The doxygen comment style also helps to keep related functions together in the generated documentation.
Just my style - I'm not suggesting that it's better than anyone else's.
stober
February 23rd, 2006, 05:55 AM
My compiler (VC++ 6.0) always gives me errors if I don't use virtual keyword in derived class -- so I just copy-paste from base class where pure virtual function is declared into implementation derived class then remove "= 0" part. I know that compiler is old and not very well compliant.
Graham
February 23rd, 2006, 09:53 AM
My compiler (VC++ 6.0) always gives me errors if I don't use virtual keyword in derived class -- so I just copy-paste from base class where pure virtual function is declared into implementation derived class then remove "= 0" part. I know that compiler is old and not very well compliant.
I use VC6 and don't have that problem...
googler
February 23rd, 2006, 02:54 PM
According to them once something is virtual it will always be which means to me it can therefore not be inlined and will always require a vtable.
The compiler is allowed (but not required) to bind calls to virtual functions at compile time (i.e. call them non-virtually) if it can determine the exact type of the object on which the function is being called at compile time. In your example it can. In constructors it also can (since in constructors, this is always assumed to point to an object whose exact type is the one being constructed. similary for destructors.)
I think that's what you meant by inlining (calling non-virtually.) However inlining has a different meaning. If the compiler can bind the virtual call at compile-time and if the body of the target function is available for inlining, it's allowed (although again, not required) to inline the called function into the calling function. In your example B::foo is available, so it may get inlined into the body of main.
Whenever you want to know what your compiler is doing with your code, it's best to generate an assembly language listing, or disassemble the object file and see for yourself what kind of code was generated.
RoboTact
February 23rd, 2006, 07:48 PM
According to them once something is virtual it will always be which means to me it can therefore not be inlined and will always require a vtable. However, I always thought that in the following example the call to b.foo() would be inlined.So your confusion has nothing to do with mozilla FAQ... C++ standard doesn't define implementation of code (generated by compilers), it only define behaviour. So when something may be optimized, it can be optimized. Compiler may even estimate that in most cases object has certain type and inline anyway, adding befor it single check for other cases.
kempofighter
February 27th, 2006, 05:32 PM
I understand why someone would have their own personal style with comments. But if you develop code that other people might someday maintain, PLEASE put the virtual key word in derived classes. Why would one think that less information would be clearer? Many professionals end up having to maintain some amount of code that someone else wrote. Complex inheritance hierachies can be terribly difficult to maintain. If the function is virtual, mark it virtual so that I don't have to go up 4 levels in base classes to figure out if something is virtual.
The only reason I could think to not use virtual is if there is a structural reason for doing so. If a class was designed so that it could exist by itself or inherit from something, I could understand not using virtual in the derived class declarations. Most of the time if I am implementing a base class with a derived class, I am going to always use that class as a derived class anyway; so what good does it do me to purposely omit the virtual keyword from the derived class function declarations? Seriously, if someone could please explain the benefit of omitting the keyword, I'd appreciate it. Maybe there is something I can learn about C++ from this thread.
My preferred style is to only use virtual when the function is first introduced, and to clearly mark out the overrides in derived classes (but without the virtual):
class foo1
{
public:
virtual int foo1m1(int) = 0;
virtual void foo2m2() = 0;
};
class foo2
{
public:
virtual int foo2m1() = 0;
};
class bar : public foo1, public foo2
{
public:
// bar's own functions
public:
//! @name From foo1
//@{
int foo1m1(int);
void foo1m2();
//@}
public:
//! @name From foo2
//@{
int foo2m1();
//@}
};
Note the redundant use of the access specifier - I use it to clearly mark different conceptual sections of the class interface (I'll also use separate privates for private functions and private data). The doxygen comment style also helps to keep related functions together in the generated documentation.
Just my style - I'm not suggesting that it's better than anyone else's.
Graham
February 27th, 2006, 05:39 PM
Please note the last sentence of my post.
I might also point out that that particular style is part of the Symbian coding guidelines...
kempofighter
February 27th, 2006, 05:51 PM
I understand that it is preference. I'm just curious as to *why* it is a preference and why it would be part of a coding standard. I've worked in a lot of large organizations where people code like this and it seems harder to understand the code. You end up having to chase the first declaration of a function up the inheritance ladder until you find the first declaration in order to verify that a particular function is virtual. I wasn't trying to insult your preference; I'm trying to understand the reasoning of this preference. So again; if anyone has any ideas on that, I'd appreciate it. Sometimes we just follow guidelines without knowing why. In this case, I don't like the guideline, personally, but if there is a good reason to use it I'd like to know what it is.
Best Regards,
Shawn
RoboTact
February 27th, 2006, 05:58 PM
Actually with modern IDEs who's going to look in 4 files to determine if something's virtual function? It's all visualized in place already...
But I see no reason for ommiting virtual keyword either. Inheritance is breaking of encapsulation already, so it's better to emphasize on where it intervenes.
exterminator
February 28th, 2006, 12:05 AM
I understand that it is preference. I'm just curious as to *why* it is a preference and why it would be part of a coding standard. I've worked in a lot of large organizations where people code like this and it seems harder to understand the code. You end up having to chase the first declaration of a function up the inheritance ladder until you find the first declaration in order to verify that a particular function is virtual. I wasn't trying to insult your preference; I'm trying to understand the reasoning of this preference. So again; if anyone has any ideas on that, I'd appreciate it. Sometimes we just follow guidelines without knowing why. In this case, I don't like the guideline, personally, but if there is a good reason to use it I'd like to know what it is.Actually with modern IDEs who's going to look in 4 files to determine if something's virtual function? It's all visualized in place already...
But I see no reason for ommiting virtual keyword either. Inheritance is breaking of encapsulation already, so it's better to emphasize on where it intervenes.There could be cases when you omit the keyword .. just to differentiate a virtual function from the most-derived class and a virtual function introduced in the middle of the hierarchy. I know, you may say that the classes deriving from that intermediate one doesnot need to know where the roots of that virtual are but still it does make sense to me.
Guidelines are just guidelines - they are not standards. Graham said it was a coding guideline and not a coding standard. There is difference between the two. With a guideline - if you feel you want to over-ride it for the better sense.. do it. I don't think there is a problem but you got to mention it somewhere. Regards.
Graham
February 28th, 2006, 03:37 AM
I understand that it is preference. I'm just curious as to *why* it is a preference and why it would be part of a coding standard. I've worked in a lot of large organizations where people code like this and it seems harder to understand the code. You end up having to chase the first declaration of a function up the inheritance ladder until you find the first declaration in order to verify that a particular function is virtual. I wasn't trying to insult your preference; I'm trying to understand the reasoning of this preference. So again; if anyone has any ideas on that, I'd appreciate it. Sometimes we just follow guidelines without knowing why. In this case, I don't like the guideline, personally, but if there is a good reason to use it I'd like to know what it is.
Best Regards,
Shawn
You know it's virtual because of the comment "From foo" and the enclosing doxygen braces, plus the fact that foo appears in the base class list for that class, so there is no "chasing around" to find out whether it's virtual - you know, and you know where it came from. The virtual keyword in this case is redundant, and I simply prefer to leave it off - YMMV. Note also that this style groups related functions (i.e. those from the same base class) together in the generated doxygen documentation, whereas not doing this could leave them spread out according to alphabetical order.
Compare that to:
class bar : public foo
{
public:
// ...
virtual void f();
};
does f() come from foo or has it been introduced by bar? What has the "virtual" added to your understanding that a well-placed comment couldn't do more effectively? And if you add the comment, why do you need the "virtual" - it's redundant.
Add the "virtual" if you wish, but a comment that says "the following functions are overrides of virtuals from base class X" is, to my mind, much clearer and more useful, and it reduces the amount of "chasing around header files" that you have to do.
codeguru.com
Copyright Internet.com Inc., All Rights Reserved.