Sign in to follow this  
CRACK123

Virtual keyword and functions

Recommended Posts

CRACK123    235
Hey, I had a real simple question about the virtual keyword. Lets say I have the following base class and a derived class
class A {
    public :
         virtual void Create() { }
};

class B : public A {
    public :
        virtual void Create() { }
};

Now what I wanted to know was - if I do something like the following
A *a = new B;
a->Create();
Now it seems to call the right Create function. If I remove the virtual keyword it still calls the right function. So it is necessary to have the virtual keyword in the derived class ? Secondly what could be the drawbacks be of not having the virtual keyword in the derived class. Thank you.

Share this post


Link to post
Share on other sites
Skizz    794
The virtual keyword is not required for derived classes. I guess most programmers use it for either consistancy or as a reminder that the function is an implementation of a base class virtual function. It maked no difference to the code if you put virtual in the derived class or not.

Skizz

Share this post


Link to post
Share on other sites
OnesAndZeros    122
Like Skizz said, the virtual keyword is not required for derived classes. However, by leaving it in, you can further derive classes (in your example, you can create a class C derived from B with a public method called Create).

Share this post


Link to post
Share on other sites
CRACK123    235
Hey,

S what you are saying is, If I do something like this


class A {
public :
virtual void Create();
};

class B : public A{
public :
void Create();
};

class C : public B{
public :
void Create();
};



Now this will give an error. Right?

Thanks.

Share this post


Link to post
Share on other sites
rypyr    252
Quote:
Original post by tomek_zielinski
It won't giv you compile-time error but :

A *a = new C;

A->Create(); // B::Create is called here, because B::Create isn't virtual and threrefore C::Create do not 'inherit' from it



Wrong.


class Base {
public:
virtual void blah() { cout << "Base" << endl; }
};

class Child {
public:
void blah() { cout << "Child" << endl; }
};

class Grandchild {
public:
void blah() { cout << "Grandchild" << endl; }
};


Try it:

Base* b = new Grandchild();
b->blah();

It should output "Grandchild".

Regards,
Jeff

Share this post


Link to post
Share on other sites
Auron    328
Plus if you make a function pure virtual, by typing:
virtual void Create () = 0;

you've made the class into an interface and so it will give errors if you try to instantiate that class. But any classes derived from it containing no pure virtual functions can be instantiated. This also means that you have to supply an implementation of any pure virtual functions from its base class, even if your implementation is a no-op.

-Auron

Share this post


Link to post
Share on other sites
rypyr    252
Quote:
Original post by Auron
Plus if you make a function pure virtual, by typing:
virtual void Create () = 0;

you've made the class into an interface and so it will give errors if you try to instantiate that class. But any classes derived from it containing no pure virtual functions can be instantiated. This also means that you have to supply an implementation of any pure virtual functions from its base class, even if your implementation is a no-op.

-Auron


Yes, but this is outside of the original question about virtual functions though.

Sometimes you want the base class to implement the function as a no-op so that you can instantiate an instance of a base class object, so it's not always the case that you want the function to be pure virtual.

Share this post


Link to post
Share on other sites
Auron    328
Very true. I was more mentioning it as a case wherein the virtual keyword is necessary (at least if your design would predicate that the base class never be instantiated).

-Auron

Share this post


Link to post
Share on other sites
Quote:


Quote:
Quote:
Original post by tomek_zielinski
It won't giv you compile-time error but :

A *a = new C;

A->Create(); // B::Create is called here, because B::Create isn't virtual and threrefore C::Create do not 'inherit' from it



Wrong.

class Base {
public:
virtual void blah() { cout << "Base" << endl; }
};

class Child {
public:
void blah() { cout << "Child" << endl; }
};

class Grandchild {
public:
void blah() { cout << "Grandchild" << endl; }
};



Try it:

Base* b = new Grandchild();
b->blah();

It should output "Grandchild".

Regards,
Jeff



Sorry - my mistake. So I guess in such a case you cannot access Child::blah()??

Share this post


Link to post
Share on other sites
rypyr    252
Quote:
Original post by tomek_zielinski
Sorry - my mistake. So I guess in such a case you cannot access Child::blah()??


From within the derived class it is possible by saying Child::blah(), but from the outside, I don't believe so. Any takers on this one?

Regards,
Jeff

Share this post


Link to post
Share on other sites
petewood    819
Quote:
Original post by tomek_zielinski
Sorry - my mistake. So I guess in such a case you cannot access Child::blah()??


You need to stop guessing.

You can access functions by being explicit.

Child::blah() will call the correct function.
Child* b = new Grandchild();
b->Child::blah();


You can access the base functions from the derived functions similarly:
void Grandchild::blah() {
Child::blah();
}


eidt: sorry, my error, b should be pointing to a Child not a Base. Didn't read it properly.

[Edited by - petewood on July 7, 2004 12:01:41 PM]

Share this post


Link to post
Share on other sites
rypyr    252
Typically when designing such a hierarchy though it is not an issue. Your subclasses usually need to call the parent's functions internally in some form (i.e. it is not a replacement for the base code but an enhancement to it).

Such as:


class Component {
RECT bounds;
public:
virtual void draw() { invalidate bounds for repainting }
};

class Window : public Component {
vector<Component*> myComponents;
public:
void draw() {
Component::draw();
// draw contents of window, pseudo-code
foreach(myComponents.begin(), myComponents.end(); Component::draw);
}
};

class FrameWindow : public Window {
public:
void draw() {
Window::draw();
// draw border, title bar, resizing widget, etc
}
};


If the client has a Component, all he needs to do is call draw(), he should never have to draw Window::draw() directly on that Component object (assuming he somehow knows that it is a Window in the first place).

Regards,
Jeff

Share this post


Link to post
Share on other sites
rypyr    252
Quote:
Original post by petewood
b->Child::blah();


Interesting...

And ugly...

What if b is not a Child? Does the runtime throw an exception? Does it do the implicit cast and then crap itself?

But I guess I can see how in some cases that might be useful.

Regards,
Jeff

Share this post


Link to post
Share on other sites
Sneftel    1788
Quote:
Original post by rypyr
What if b is not a Child? Does the runtime throw an exception? Does it do the implicit cast and then crap itself?

It has to be. This will cause a compile error:

class A { virtual void foo(); };
class B : public A { virtual void foo(); };
int main() {
A *a = new B;
a->B::foo(); // ERROR
}

The explicitly scoped function must exist in either the class or one of its ancestors. Thus, no casting is actually being done; you're simply invoking a particular function.

Share this post


Link to post
Share on other sites
rypyr    252
Sneftel, I'm assuming you forgot the "public" specifier here for the foo function in both class definitions...

What I'm asking for is this situation:


class A {public: virtual void foo() {}};
class B : public A {public: void foo() {}};
class C : public B {public: void foo() {}};

void invoke(A* obj) {
A* a = new C;
a->B::foo(); // no error here because compiler knows the actual type at compile-time?

obj->B::foo(); // error here because compiler can't determine the actual type at compile-time?
}


Are my comments correct?

Thanks,
Jeff

Share this post


Link to post
Share on other sites
rypyr    252
Also, was your example correct, because 'a' actually is an object of type B, so I'm not sure why that would cause an error as you indicate.

Share this post


Link to post
Share on other sites
Sneftel    1788
Quote:
Original post by rypyr
class A {public: virtual void foo() {}};
class B : public A {public: void foo() {}};
class C : public B {public: void foo() {}};

void invoke(A* obj) {
A* a = new C;
a->B::foo(); // no error here because compiler knows the actual type at compile-time?
No, the compiler doesn't know the actual type. I mean, in that particular situation it could probably figure it out if it tried really hard, but consider if the initialization of a took place in a different function. The compiler only "knows" as much about a type as you directly tell it by defining that type.

Share this post


Link to post
Share on other sites
Sneftel    1788
Quote:
Original post by rypyr
Also, was your example correct, because 'a' actually is an object of type B, so I'm not sure why that would cause an error as you indicate.
Because the compiler can't tell for sure that it is. All the compiler knows is that "a" is a pointer to an object of class "A".

Share this post


Link to post
Share on other sites
CRACK123    235
This doesn't compile at all. Both give compiler errors.

The following are the errors on compiling.
Quote:

test.cpp:12: type `B' is not a base type for type `A'
test.cpp:14: type `B' is not a base type for type `A'


Wouldn't that actually defeat the purpose of virtual keyword. If you do want to call base class foo, why not do it the virtual function itself ?


Quote:
Original post by rypyr
Sneftel, I'm assuming you forgot the "public" specifier here for the foo function in both class definitions...

What I'm asking for is this situation:

*** Source Snippet Removed ***

Are my comments correct?

Thanks,
Jeff

Share this post


Link to post
Share on other sites
petewood    819
Quote:
Original post by rypyr
Quote:
Original post by petewood
b->Child::blah();


Interesting...

And ugly...

Regards,
Jeff

Sorry, I'm wrong. See original post.

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this