Why can't one store an object as it's base virtual class ?
Consider the following example : It will segfault if Derived inherits virtually of Base
#include <iostream>
#include <memory>
class Base
{
public:
virtual ~Base() = default;
int baseInt = 42;
};
class Derived : public /* virtual */ Base // <<< Uncomment the virtual to get a segfault
{
public:
int derivedInt = 84;
};
int main()
{
Base *base_ptr = new Derived();
Derived *derived_ptr = reinterpret_cast<Derived *>(base_ptr);
std::cout << " baseInt is " << derived_ptr->baseInt
<< ", derivedInt is " << derived_ptr->derivedInt << std::endl; // segv on this line
}
The reinterpret_cast you used simply uses the Base pointer as if it were a Derived pointer.
Instead, this is one of the few situations where you should use a dynamic_cast.
The example in the documentation for dynamic_cast shows such a downcast.
Related
I have following code snippet:
class base
{
public:
virtual void print(char a){ std::cout << " Base\n"; }
};
class derived : public base
{
public:
void print(float a) { std::cout << " Derived\n"; }
};
int main() {
base* d = new derived;
d->print(1.5);
}
Output is Base.
Why is the output coming from the base function and not from the derived one?
You have not overridden the function in the base class, you have overloaded it: The version in the derived class takes a float as an argument, and is quite a different beast from the base class method which takes a char. Moreover, the float version in the derived class shadows the base class version: The base class version becomes inaccessible for calls on the derived type.
As such, the following code
Derived d;
d.print('a');
d.print(1.5);
will print
Derived
Derived
because the call is resolved by the compiler to the only version of print() that's available in Derived.
Likewise, when you call d->print(1.5) through a pointer to Base, the derived class' version is inaccessible to the call: The compiler looks at the base class, sees that there is no print() method defined with a float argument, and converts the argument to char instead. It then calls the only implementation of print(char), which happens to be supplied by the base class.
If you simply change the signature of the print() method in the derived class to match that of the base class, the odd behavior will go away.
When you declare Base* d = new Derived;, the type of the class is Base, as printed by typeid(d).name(), so this instance doesn't have access to child class methods. If you change the type to Derived, you'll call the child method:
#include <iostream>
#include <typeinfo>
class Base
{
public:
virtual void print(char a) {
std::cout << " Base " << std::endl;
}
};
class Derived : public Base
{
public:
void print(float a) {
std::cout << " Derived " << std::endl;
}
};
int main()
{
Derived* d = new Derived;
std::cout << "class type is: " << typeid(d).name() << std::endl;
d->print(1.5);
return 0;
}
Output:
class type is: P7Derived
Derived
Furthermore, declaring the parent class print method virtual doesn't allow an instance of Base to call the child version of print because the child hasn't overridden it (different headers). Creating an instance of Base with Base *d = new Derived; and changing the Derived print method header to void print(char a) in the Derived class would allow you to call the child print method and output Derived, even from an instance of Base, using the virtual keyword.
#include <iostream>
#include <typeinfo>
class Base
{
public:
virtual void print(char a) {
std::cout << " Base " << std::endl;
}
};
class Derived : public Base
{
public:
void print(char a) {
std::cout << " Derived " << std::endl;
}
};
int main()
{
Base* d = new Derived;
std::cout << "class type is: " << typeid(d).name() << std::endl;
d->print(1.5);
return 0;
}
Output:
class type is: P4Base
Derived
I saw this example:
http://www.cplusplus.com/doc/tutorial/typecasting/#dynamic_cast
(...)
class Base { virtual void dummy() {} };
class Derived: public Base { int a; };
(...)
Base * pba = new Derived;
Base * pbb = new Base;
(...)
Why 'pba' is a Base object if it's being initialized with Derived? Why not make it a Derived object?
Derived * pba = new Derived; // use this instead
And is it just a C++ thing?
neither pba nor pbb is an object but they are pointers of type base class Base so in your code you used he pointers polymorphically which means a base pointer can point to the same class or to its derived class object.
the object is created with new not pbb or pba themselves, consider this example:
#include <string>
#include <iostream>
using namespace std;
class Base
{
public:
virtual void Print() const { cout << "Base print()" << endl;} // virtual function
void Greet()const {cout << "in Base Say: hello!" << endl;}
};
class Derived : public Base
{
public:
void Print() const { cout << "Derived print()" << endl;} // ovrode the base member pritn()
void Greet()const {cout << "in Derived Say: hello!" << endl;}
};
int main()
{
Base* pba = new Derived;
pba->Print(); // Derived print()
pba->Greet(); // in Base Say: hello! ??? because Greet() is not virtual
Base* pbb = new Base;
pbb->Print(); // Base print()
pbb->Greet(); // in Base Say: hello!
return 0;
}
so at runtime the pointer pba and pbb can be assigned an object of Base or Derived classes thus the virtual member function are called accordingly.
I have an class which inherit two interfaces:
class Multi : public IFoo, public IBar {
public:
virtual ~Multi();
// Foo part
virtual void fooMethod();
// ...
// Bar part
virtual void barMethod();
// ...
};
Unfortunately this class cannot be decomposed in two separate classes for each interface. In fact in class implementation those entities (Foo and Bar) are tightly coupled, but in future they could become separate.
Another one class wants to use Multi class, having a pointer to IFoo and IBar:
class ClientClass {
public:
ClientClass(); // constructor
// smth
private:
std::shared_ptr<IFoo> foo_;
std::shared_ptr<IBar> bar_;
};
In constructor I do something like:
ClientClass::ClientClass(){
auto pMulti = new Multi;
foo_ = std::shared_ptr<IFoo>(pMulti);
bar_= std::shared_ptr<IBar>(pMulti);
}
But each of those shared pointers has separate reference counter, and it leads to deleting already deleted pointer on class destruction, am I right?
How should I treat it?
What is best practics for such case?
ClientClass::ClientClass()
{
auto pMulti = std::make_shared<Multi>();
foo_ = pMulti;
bar_ = pMulti;
}
would ensure that they have the same reference counter. You can see it for yourself:
#include <iostream>
#include <memory>
class Base1{};
class Base2{};
class Derived : public Base1, public Base2 {};
int main()
{
auto derived = std::make_shared<Derived>();
std::shared_ptr<Base1> base1 = derived;
std::shared_ptr<Base2> base2 = derived;
std::cout << "base1 usecount = " << base1.use_count() << '\n';
std::cout << "base2 usecount = " << base2.use_count() << '\n';
std::cout << "derived usecount = " << derived.use_count() << '\n';
return 0;
}
produces:
base1 usecount = 3
base2 usecount = 3
derived usecount = 3
I don't know exactly what you want to do with those pointers, but an alternative solution may be to store a std::unique_ptr<multi> multi_; and have a couple of interface functions that static cast it to plain pointers or to references:
IFoo& ClientClass::get_ifoo() {
return *(static_cast<IFoo*>(multi_.get()));
}
IBar& ClientClass::get_ibar() {
return *(static_cast<IBar*>(multi_.get()));
}
As long as you don't pass those out from the class, and don't call delete[] on them it should be quite safe.
Is it possible to get a base's derived class's type name by using typeid( TYPE ).name() ?
Example of pushing a base pointer back into a derived pointer, statically.
#include <iostream>
#include <typeinfo>
class base
{
public:
virtual void known() = 0;
};
class derived: public base
{
public:
void known() { std::cout << " I guess this means "; }
void unknown(){ known(); std::cout << " its possible "; }
};
int main()
{
derived d;
std::cout << typeid( d ).name() << std::endl;
// Prints out being a pointer to a derived class
base* b = &d;
std::cout << typeid( b ).name() << std::endl;
// Prints out being a pointer to a base class
// But how would you use it, or in any other way,
//get the original derived type name
derived * db = (derived*) b;
// db is casted at at compile time, the derived class is known
db->unknown();
}
Given an expression whose type is a polymorphic base class, The result of the typeid operator refers to a std::type_info object representing the type of the most derived object.
Example:
#include <iostream>
#include <typeinfo>
class Base {
public:
virtual ~Base() {}
}; // Base
class Derived : public Base {};
int main() {
Derived derived;
/* By reference. */ {
Base &base = derived;
std::cout << typeid(base).name() << std::endl;
}
/* By pointer. */ {
Base *base = &derived;
std::cout << typeid(*base).name() << std::endl;
// NOTE: typeid(base).name() results in printing of the Base class' name.
}
}
Both cases above print the Derived class' name.
References
N3797: 5.2.8 Type identification.
cppreference: 2) a)
I have a simple code which doesn't work correctly with reference (polymorphism).
#include <iostream>
#include <string>
class Base {
public:
Base() {}
virtual ~Base() {}
virtual std::string text() const {
return "Base";
}
};
class Derived: public Base {
public:
Derived(Base& _b): b(_b) {}
virtual ~Derived() {}
virtual std::string text() const {
return b.text() + " - Derived";
}
private:
Base& b;
};
int main(int argc, char const *argv[])
{
Base b;
Derived d1(b);
std::cout << d1.text() << std::endl;
Derived d2(d1);
std::cout << d2.text() << std::endl;
return 0;
}
And output:
Base - Derived
Base - Derived
The second line in output I expected: Base - Derived - Derived. I read some resources and polymorphism work perfectly with reference and pointer but in this situation, it doesn't. If I replace reference by pointer, it work again. So, anybody can give me some explainations?
Thanks so much!
You're invoking the default copy constructor to Derived. Therefore when finished d2 will be a simple member-copy of d1, and both their b members will reference the same Base instance.
To prove this, add this to your Derived class
class Derived: public Base {
public:
Derived(Derived& d) : b(d) {}
Derived(Base& _b): b(_b) {}
virtual ~Derived() {}
virtual std::string text() const {
return b.text() + " - Derived";
}
private:
Base& b;
};
With this your output will become:
Base - Derived
Base - Derived - Derived
And just note, this is not a grand idea or a stellar learning example of polymorphism. (But it is an interesting example of construction overriding). Also note this is NOT a typical override of default copy-construction (where the parameter is a const-ref-type). Thus part of the reason this is not the greatest sample.
If you instrument the code you will see that when you call Derived d2(d1) the Derived::Derived(Base&)
constructor is not being called. This is because the d1 argument is a better match for the
implicit copy constructor, which just copies the b member from d1 to d2.
In order to see the behavior you expect, you can explicitly cast the d1 to (Base&)d1. If you do
so you will get code like the following (with the instrumentation):
#include <iostream>
#include <string>
class Base {
public:
Base() {}
virtual ~Base() {}
virtual std::string text() const {
return "Base";
}
};
class Derived: public Base {
public:
Derived(Base& _b): b(_b) {std::cout << "init'ed with: " << _b.text() << std::endl;}
virtual ~Derived() {}
virtual std::string text() const {
return b.text() + " - Derived";
}
private:
Base& b;
};
int main(int argc, char const *argv[])
{
std::cout << "Creating Base" << std::endl;
Base b;
std::cout << "Creating d1" << std::endl;
Derived d1(b);
std::cout << d1.text() << std::endl;
std::cout << "Creating d2" << std::endl;
Derived d2(d1);
std::cout << d2.text() << std::endl;
std::cout << "Creating d3" << std::endl;
Derived d3((Base&)d1);
std::cout << d3.text() << std::endl;
return 0;
}
And this gives the expected output:
Creating Base
Creating d1
init'ed with: Base
Base - Derived
Creating d2
Base - Derived
Creating d3
init'ed with: Base - Derived
Base - Derived - Derived
Your d1 and d2 both have type Derived so this is working correctly. Typically the references are reversed; e.g.
Base b;
Derived d;
Base &dr = d;
std::cout << b.text() << std::endl;
std::cout << dr.text() << std::endl;
Here text() is invoked through a Base type but the latter will call the version in Derived.
Note that it doesn't typically make sense to allow a derived class to be initialized via a base class. Suppose you add type Derived2 that has abilities or state much different from Derived. This constructor would allow
Derived2 d2;
Derived d1(d2);
which is likely a very bad idea.
As noted correctly in the comment, it is now using the default copy constructor, and that is the reason for your observation with the same output for both. So, d1 is just copied into d2 rather than used for the base member variable inside d2.