Few Basic Questions in Overriding
I have few problems with my basic and would be thankful if someone can clear this.
1: What does it mean when I say base *b = new derived; Why would one go for this? We very well separately can create objects for class base and class derived and then call the functions accordingly. I know that this base *b = new derived; is called as Object Slicing but why and when would one go for this?
2: I know why it is not advisable to convert the base class object to derived class object (because base class is not aware of the derived class members and methods). I even read in other StackOverflow threads that if this is gonna be the case then we have to change/re-visit our design. I understand all that, however, I am just curious, Is there any way to do this?
class base
{
public:
void f(){cout << "In Base";}
};
class derived:public base
{
public:
void f(){cout << "In Derived";}
};
int _tmain(int argc, _TCHAR* argv[])
{
base b1, b2;
derived d1, d2;
b2 = d1;
d2 = reinterpret_cast<derived*>(b1); //gives error C2440
b1.f(); // Prints In Base
d1.f(); // Prints In Derived
b2.f(); // Prints In Base
d1.base::f(); //Prints In Base
d2.f();
getch();
return 0;
}
3: In case of my above example, is there any way I could call the base class f() using derived class object? I used d1.base()::f() I just want to know i开发者_如何学Pythonf there any way without using scope resolution operator?
Thanks a lot for your time in helping me out!
1. This is not object slicing:
base *b = new derived;
This is assigning a pointer of type base
to an instance of derived
.
One (very common) example of this in action is in callbacks. Consider this:
class Observer
{
public:
virtual void OnEvent() = 0;
};
class Subject
{
public:
Subject() : observer(0) {}
void SetObserver(Observer* o) { observer = o; }
void FireEvent() { if(observer != 0) observer->OnEvent(); }
private:
Observer* observer;
};
class MyObserver : public Observer
{
public:
void OnEvent() { ::printf("Hi there!\n"); }
};
int main()
{
Subject s;
MyObserver o;
s.SetObserver(&o);
s.FireEvent();
return 0;
}
This should be the expected output:
Hi there!
Notice what is happening here. We're passing in a pointer to an instance of MyObserver
to SetObserver()
even though the function only accepts pointers of type Observer
. This works because MyObserver
(publicly) derives from Observer
. In this case, we say that MyObserver
is-an Observer
.
The Observer
type defines a pure virtual function (The =0
means that the function is pure; it must be implemented by derived classes). The virtual
keyword tells the compiler that calling the function should cause the most-derived function to be executed. The OnEvent()
function in MyObserver
is the most-derived, therefore, that version is called, even though we are calling OnEvent()
on a pointer of type Observer
.
We go through the trouble of doing all this because in this code Subject
doesn't have to know the exact type of its observer - the observers just have to derive from Observer
and the Subject
instance will call the most derived type's implementation of OnEvent()
. This allows for code decoupling - Subject
doesn't depend on MyObserver
, and MyObserver
doesn't depend on Subject
.
2. There's nothing wrong with casting a pointer from a base to derived type per se. The following is in fact legal and guaranteed to work:
class Base {};
class Derived : public Base {};
int main()
{
Derived d;
Base* bp = &d;
Derived* dp = static_cast<Derived*>(bp);
return 0;
}
The line before the return statement in this snippet, however, is undefined:
class Base {};
class Derived1 : public Base {};
class Derived2 : public Base {};
int main()
{
Derived1 d1;
Base* bp = &d1;
Derived2* d2p = static_cast<Derived2*>(bp); // WTF?!
return 0;
}
The value of the d2p
pointer is meaningless, and attempting to access anything in it will certainly cause a crash, because the bp
pointer doesn't actually point to a Derived2
instance, it points to a Derived1
instance. Compilers cannot catch this at compile time, because both Derived1
and Derived2
inherit from Base
, so the cast successfully compiles. This is the main danger with casting from a base to a derived type - you won't know until runtime if the cast actually returns meaningful results.
Of course, unless you use dynamic_cast<>()
, but the cast incurs a runtime penalty. static_cast<>()
involves at most, pointer arithmetic. reinterpret_cast<>()
forces a pointer to take on a different (potentially unrelated) type, without performing any pointer arithmetic. This makes reinterpret_cast<>()
one of the more dangerous casts and should be used only when necessary, especially if static_cast<>()
can do the job.
3. Consider the following:
class Base
{
public:
void Foobar() { ::printf("In Base!\n"); }
};
class Derived : public Base
{
public:
void Foobar() { ::printf("In Derived!\n"); }
};
int main()
{
Derived d;
Derived* dp = &d;
Base* bp = dp;
dp->Foobar();
bp->Foobar();
return 0;
}
If the Foobar()
function is not virtual, then you will get this output:
In Derived!
In Base!
Otherwise, if the Foobar()
function is virtual, then you will get this output:
In Derived!
In Derived!
To guarantee that a call to the virtual function Foobar()
invokes the base implementation via the base pointer, then you have to use the scope resolution operator:
// Prints "In Base!", even if bp actually points
// to an instance of Derived overriding Foobar().
bp->Base::Foobar();
Yes and no. You can go
class derived: public base {
public: void f() { base::f(); }
};
I'm not too sure about at a global scope though.
Question 1: Why would you do this: you probably wouldn't do this directly. The case where this would happen would be where you had, for example, a function that returns "some kind of base*" and you don't care which type.
Question2: from within derived, you need to use the scope resolution operator to specify that you want to use the base class' implementation.
Note: you have not declared your function virtual, so you are not actually going to get the behavior you are expecting.
base *b = new derived
Creating Base class pointer that points to derived class object. This allows you to create is-a relationship. Class Derived is a Base. Please refer inhertance for more details.
2. d2 = reinterpret_cast<derived*>(b1);
You are trying to convert a base class object to derived class object. But the cast operation used is . Its not correct.
If you are planning to call base class method then use Base class pointers.
Base* ptr = &b1;
ptr->f();
I recommend you to refer FAQ Lite.
base *b = new derived;
(1) You are having a base class pointer point to a derived class object. This is used when implementing polymorphism where you have several derived classes which inherits from a common base class. You can then call the correct derived classes' function according to its type through the base class pointer, provided the function is virtual.
class base
{
public:
virtual void f(){ cout << "In Base" << endl; }
};
class derived:public base
{
public:
void f(){ cout << "In Derived" << endl; }
};
class derived2: public derived
{
public:
void f() { cout << "In Derived2" << endl; }
};
int _tmain(int argc, _TCHAR* argv[])
{
derived d1;
derived2 d2;
base* b;
b = &d1;
b->f(); // calls derived::f();
b = &d2;
b->f(); // calls derived2::f();
return 0;
}
And it is not called object slicing. Object slicing is when you assign a derived class object to a base class object (not pointers) where in the members of the derived class object are sliced, left off. Because of this, you cannot access those sliced members from the base class object.
(2) The other statements are fine except for the line using reinterpret_cast.
(3) You'll have to use the scope resolution operator if you're using objects or override the derived class function to call the base class version (like mentioned in other answers). However, you can use pointers:
derived *d = static_cast( &b1 );
d->f();
精彩评论