Let A be the base class and B be it's publicly derived class.
B b;
Slicing:
A a = b;
Upcasting:
A* p = &b; // p is a pointer variable of type A
A& r = b; // r is a reference variable of type A
Is this correct? Please share similar examples to illustrate the two concepts if possible.
Yes!
Object slicing happens when a derived class object is assigned to a base class object, additional attributes of a derived class object are sliced off to form the base class object.
So yes, if you have a base class A
class A{
public:
int x;
char y;
};
and a class B derived publically from A with some extra data members,
class B:public A{
public:
int z;
};
doing A a = b; will slice off 'z'.
Upcasting is conversion of pointer or reference of derived class type to pointer or reference of base class type, going up in the inheritance tree.
B objB;
A *objA = &objB;
Just to bring more light on this subject, you can convert a base-class pointer(reference) to a derived-class pointer (reference).It is called downcasting(opposite to upcasting).
B *objB = (B *) &A;
But there's no way you can assign a base class object to a derived class object.
Cheers!
Related
class a{};
class b : public class a{
public:
int c;
};
a* var = new b;
var->c=2;
Last line is not correct. Is it possible to refer to the derived class member?
while var is a b object at compile time the compiler does not know that so you have to cast it to a b object or pointer like this.
(*(b*)var).c = 2;
((b*)var)->c = 2;
My computer science teacher explained that treat two cases when doing polymorphism run-time and compile time
Hope this helps.
If the member is not in the base class, you should not be allowed to access it and it should give a compilation error. To access a member of derived class, you can typecast it to the derived class.
class a{};
class b : public class a{
public:
int c;
};
a* var = new b;
((b*)var)->c=2;
You can use static_cast to downcast from Base to Derived and then access the member.
static_cast<b*>(var)->c = 2;
I have the following code.
#include <iostream>
using namespace std;
class Base
{
public:
virtual int f(){cout<<"Base"<<endl;}
};
class Derived:public Base
{
public:
int f(){cout<<"Derived"<<endl;}
};
int main()
{
Base b;
Derived d;
b.f(); ///base
((Base)d).f(); ///base
cout<<"----------------"<<endl;
Base *b1 = new Base;
Base *b2 = new Derived;
Derived *d1 = new Derived;
b1->f(); ///base
((Base*)d1)->f(); ///derived
((Base*)b2)->f(); ///derived
static_cast<Base*>(d1);
d1->f();///derived
static_cast<Base*>(b2);
b2->f();///derived
cout<<"----------------"<<endl;
Base *b5 = dynamic_cast<Base*>(b2);
Base *b6 = dynamic_cast<Base*>(d1);
if(b5)
b5->f(); ///derived
if(b6)
b6->f(); ///derived
return 0;
}
I want to ask why the derived *d1 OR b2 pointers when converted to a base using explicit cast (Base), static cast (static_cast(d1)) or dynamic cast (dynamic_cast(d1)) won't call the f() function of the base class after the conversion. It seems to call the f() function from the derived class every single time.
Also, strangely when I declare the objects this way. The conversion works and calls the base function.
Base b;
Derived d;
b.f(); ///base
((Base)d).f(); ///base
Now, I understood that the right way to access the f() from Base class would be d->Base::f(), but why should I use dynamic_cast or static_cast since they won't convert the derived pointer to base and call the right function. I would need a detailed explanation if possible. Thanks!
Fortunately, for both you and my keyboard, the explanation is trivial:
((Base)d) slices the object d to a value-copied Base instance.
((Base*)d1)->f() will still call the derived method since Base and therefore Derived are polymorphic types, and although ((Base*)d1) is a Base* pointer, it is pointing to a Derived object. Ditto for static_cast and dynamic_cast.
Reference: https://en.wikipedia.org/wiki/Object_slicing
I'm a new user of programming c++. When I don't create a derived instance by new, it calls Base::test().
So what is the difference between Base b = d and Base* b1 = new Derived() ?
Base class
#include <iostream>
class Base
{
public:
virtual void test() { std::cout << "Base::test()" << std::endl; };
};
Derived class
#include "Base.h"
class Derived : public Base
{
public:
void test() { std::cout << "Derived::test()" << std::endl; };
}
main.cc
#include "Derived.h"
int main()
{
Derived d;
d.test();
Base b;
b = d;
b.test(); // why called Base::test() ?
Base* b1 = new Derived();
b1->test();
delete b1;
return 0;
}
Derived d;
d.test();
Base b;
b = d;
b.test(); // why called Base::test() ?
You created a Derived object d and Base object b. And later assigned b=d; Here object slicing is happening. After the assignment b has only Base part of the Derived class info in hand. So when you call b.test() it will call Base::test() instead Derived::test() function.
Base* b1 = new Derived();
b1->test();
delete b1;
Here you dynamically created a Derived class object in heap and returned the pointer of that object to Base class pointer. Here pointer is nothing but the memory address holding the Derived class object. And when you call b->test(), system internally identify the type of the object dynamically and it is returned as Derived. So it will call Derived::test() function.
Because that's not how polymorphism is implemented in C++.
This:
Base b;
b = d;
the second statement calls an assignment operator of b, i.e. b is still the same object b of class Base (except perhaps the data is now different, but the set of methods, i.e. the type is still Base).
You need to operate on pointers instead of references, because references cannot be changed and they are not changed.
You have mesh between two important concept in c++.
Run time polymorphism
Object Slicing
In c++ run time polymorphism is achieved using base class pointer with the help of virtual function. Since actual type of object is decided at run time. As we know base class pointer can store object of derived class. And then call to any function invoke call to derived class function(if base is virtual).
In you case you are assigning object of derived class to object of base class. This is Object slicing.
Is it necessary to instance the class another class has been derived from?
If I dont, I can access its methods anyway, like in this example:
#include <iostream>
struct Class1 {
public:
void func();
};
struct Class2 : public Class1 {
// Class1 c1; <-- is this necessary?
};
void Class1::func(){
std::cout << "function called" << std::endl;
}
int main() {
Class2 c2;
c2.func();
}
I get the expected function called.
But in some examples I see that the base class is being instanced in the derived class: Class1 c1;. What is it for?
Is it necessary to instance the class another class has been derived from?
No, it is absolutely not necessary.
But in some examples I see that the base class is being instanced in the derived class: Class1 c1;. What is it for?
Without knowing what those examples concretely deal with - i.e. what was the semantics of those classes - it's not easy to explain them in a meaningful way. However, when you create a data member of a certain type, your object has a sub-object of that type. So when you do:
struct Y { };
struct X
{
int a;
std::string b;
Y c;
};
Every object of type X will have a subobject a of type int, a subobject b of type b, and a subobject c of type Y. You would be accessing that with the dot notation, as done below:
Y foo();
X x;
std::cout << x.a;
x.b = "Hello, World!";
X.c = foo();
Similarly, when a class D derives from a base class B, it contains a sub-object of type B, and implicitly inherits all the data members of B:
struct B
{
int a;
std::string b;
};
struct D : B
{
bool c;
};
// ...
D d;
d.c = true;
d.b = "Hello, Base Class!";
d.a = 42;
Now in your case, the class Class2 apart from deriving from Class1 also has a data member of type Class1. Notice, that this data member is not the base sub-object of Class2, but an additional member sub-object. So what does this mean?
Take this with a grain of salt, but in order to develop intuition, you can think that inheritance models the "IS-A" relationship, while data membership models the "HAS-A" relationship.
So the fact that Class2 derives publicly from Class1 models the fact that "All Class2 objects are Class1 objects", and therefore inherit all of Class1's data members. This explains why objects of type Class2 have a base sub-object of type Class1.
On the other hand, the fact that Class2 has a data member of type Class1 models the fact that "All Class2 objects contain/embed/own an object of type Class1". This explains why objects of type Class2 have a member sub-object of type Class1.
Now in the particular case of the examples you mention both of the above semantics are modeled at the same time - i.e. a Class2 both IS-A and HAS-A Class1 - but that is by no means necessary. Not every thingy which IS-A widget also HAS-A widget.
I hope this makes sense to you in an abstract way. Whether the design is correct or not mostly depends on the semantics of your Class1 and Class2 objects, and on what they are meant to model, but the message is:
If Class2 derives from Class1, there is nothing that forces you to add a Class1 data member to Class2.
There is no need to have a base class member variable in the derived class in this case. Also polymorphism applies only for pointer and reference types.
No, it is not necessary.
class Base {
}
class Derived : public Base {
}
The Derived class will inherit the members of the Base class.
It definitely isn't necessary. Without seeing the examples you are referring to it's hard to tell why the author would have created the instance. Most likely it is to show what happens when Class2::func() calls c1.func().
Compiling f works, but compiling g fails with an error.
Why does this happen?
class A {
public:
A() {}
};
class B : public A {
public:
B() {}
};
void f() {
A* a = new A();
B* b = static_cast<B*>(a);
}
void g() {
A* a = new A();
B* b = a;
}
A static_cast forces a conversion that is potentially unsafe.
B* b = static_cast<B*>(a);
This would be valid if a pointed to an A object that actually was the base class sub-object of a B object, however it doesn't. The cast forces the conversion.
B* b = a;
There is no cast here and there is (correctly) no implicit conversion allowed from base class pointer to derived class pointer. A pointer to a derived class can always be converted to a pointer to a base class because a derived class object always contains a base class sub-object but not every base class instance is a sub-object of a particular derived class type.
Well, yeah. Doing:
B* b = new A();
Is unsafe. You end up with a B pointer to an A object; you never construct the B portion of the object; your object is "sliced".
On the other hand...
A* a = new B();
...would be fine.
You are trying to convert a pointer from A* to B*. I am not sure what you are trying to achieve. But since B* is derived from A* and not the other way around this is not valid. Maybe you want to do something like this:
int main()
{
///The above code compiles while if I replace above two line in main with below assignment it gives error.
A *a=new A();
A * b=new B();
}
Yes, it does give an error if you want to assign a base class to a derived class pointer type. No, it doesn't give an error if you explicitly cast the pointer type, because in C++ you are allowed to shoot yourself in the foot if you so desire.
What exactly is baffling you, or what did you expect to achieve with your code?
A base class cannot be implicitly converted to a derived class. Just consider this
class A {
public: int x;
};
class B : public A {
public: int y;
};
B* b = new A; // assume it works, so 4 bytes is allocated and initialized.
b->y; // bam! accessing unallocated region.