I have a C++ test next Tuesday about virtual types, inheritance, etc. My issue is that I have a strange output coming from my code, and I don't have a clue where is it coming from:
Code:
#include <iostream>
#include <typeinfo>
using std::cout; using std::endl;
template<int id> class B{
int* p;
public:
B(): p{new int}{
cout << typeid(*this).name() << "::" << typeid(*this).name() << "()" << endl;
}
B(const B& b): p{new int{*(b.p)}}{
cout << typeid(*this).name() << "::" << typeid(*this).name() << "(const " << typeid(*this).name() << "&)" << endl;
}
virtual ~B(){
delete p;
cout << typeid(*this).name() << "::~" << typeid(*this).name() << "()" << endl;
}
};
class D: public B<0>{
public:
D(){
cout << "D::D()" << endl;
}
D(const D& d): B<0>{static_cast<const B&>(d)}, b1{d.b1}, b2{d.b2}{
cout << "D::D(const D&)" << endl;
}
~D(){
cout << "D::~D()" << endl;
}
private:
B<1> b1;
B<2> b2;
};
int main()
{
B<0>& b{*new D};
cout << "-----------------------------" << endl;
D d{dynamic_cast<D&>(b)};
cout << "-----------------------------" << endl;
delete &b;
cout << "-----------------------------" << endl;
}
Output:
1BILi0EE::1BILi0EE()
1BILi1EE::1BILi1EE()
1BILi2EE::1BILi2EE()
D::D()
-----------------------------
1BILi0EE::1BILi0EE(const 1BILi0EE&)
1BILi1EE::1BILi1EE(const 1BILi1EE&)
1BILi2EE::1BILi2EE(const 1BILi2EE&)
D::D(const D&)
-----------------------------
D::~D()
1BILi2EE::~1BILi2EE()
1BILi1EE::~1BILi1EE()
1BILi0EE::~1BILi0EE()
-----------------------------
D::~D()
1BILi2EE::~1BILi2EE()
1BILi1EE::~1BILi1EE()
1BILi0EE::~1BILi0EE()
Questions:
1) Why are the names from each typeid so strange? Is there a way to calculate each one? I figured out that if I change my compiler the names change aswell.
2) Why is my program printing twice the output from my destructor from B base class. Is it related with virtual type and inheritance?
3) Can somebody explain me the benefits of using static_cast instead dynamic_cast? From every perspective I have been taught, static_cast usually have more problems in execution time vs dynamic_cast.
Thank you a lot.
Can somebody explain me the benefits of using static_cast instead dynamic_cast? From every perspective I have been taught, static_cast usually have more problems in execution time vs dynamic_cast.
The benefit of static_cast is that it is a less expensive operation but, yes, it has more problems.
Take the following simple program:
#include <iostream>
#include <typeinfo>
struct Foo
{
virtual ~Foo () {}
};
struct Bar1 : Foo
{
Bar1(int v) : v_(v) {}
int v_;
};
struct Bar2 : Foo
{
Bar2(double v) : v_(v) {}
double v_;
};
void test_static_cast(Foo& f)
{
std::cout << static_cast<Bar1&>(f).v_ << std::endl;
}
void test_dynamic_cast(Foo& f)
{
std::cout << dynamic_cast<Bar1&>(f).v_ << std::endl;
}
int main()
{
Bar1 b(10);
test_static_cast(b);
test_dynamic_cast(b);
}
The output is same regardless of whether you use static_cast or dynamic_cast. However, if you change main to use Bar2 instead of Bar1,
int main()
{
Bar2 b(10);
test_static_cast(b);
test_dynamic_cast(b);
}
the static_cast version goes into the territory of undefined behavior while the dynamic_cast version throws a std::bad_cast exception. You can deal with the exception in a predictable manner while there is no predictable behavior of the static_cast version.
Use static_cast only if are VERY CERTAIN of what you are dealing with. Otherwise, opt for the more expensive but more reliable dynamic_cast.
Related
I have this program from an exercise, and I don't understand how the static_cast is working here:
#include <iostream>
using namespace std;
class A {
public:
virtual void f() const { cout << " A::f "; }
virtual void g() { cout << " A::g "; }
virtual A* n() { cout << " A::n "; return this; }
virtual void t() { cout << " A::t "; }
};
class B: public A {
public:
virtual void f() const { cout << " B::f "; }
void g() { cout << " B::g "; A::n(); }
A* n() { cout << " B::n "; return this; }
void t() { cout << " B::t "; }
};
class C: public A {
public:
virtual void f() { cout << " C::f "; }
void g() const { cout << " C::g "; }
};
int main() {
A* q2 = new B();
A* q3 = new C();
(static_cast<C*>(q2))->g(); cout << endl;
(static_cast<C*>(q2))->t(); cout << endl;
(static_cast<B*>(q3->n()))->f(); cout << endl;
return 0;
}
The output of this is:
C::g
B::t
A::n A::f
Can someone explain how it can take the function in C if C has never been constructed for the pointer q2? How does the static_cast work in this case?
The cast does not "work". You pretend to have a pointer to an instance of C but the pointer does not point to an instance of C. Using that pointer to call a method is undefined.
Your code has undefined behavior. Compilers are not required to diagnose undefined behavior and there are no restrictions on the compilers output. The output of this code could be anything.
PS: You should use the override specifier when overriding virtual methods. In this code it looks like you wanted C::f to override A::f, but it does not, and this will become apparent when you use override.
PS2: Calling a non-static method on a pointer of wrong type can sometimes appear to work when the method is not actually using this. Thats why you see "ok" output. However, that does not make it less wrong.
I am trying to create a cast from A* to int where A is a class I've defined.
The conversion is from a lookup, (the int is the id of that A instance) in case you wanted to know.
Currently, I have:
#include <iostream>
class A{
private:
int val;
public:
A(){};
A(int val): val(val){};
static A* cast(int val){
return &(A());
//This will actually be a valid pointer
}
explicit operator int(){
return val;
}
};
int main() {
A a(7);
std::cout << "Pointer: " << &a << std::endl;
std::cout << "Pointer cast: " << A::cast(5) << std::endl; //would like this to be static_cast<A*>(5)
std::cout << "Int cast: " << static_cast<int>(a) << std::endl;
}
I can create a nice cast from A to int. However, I cannot figure out how to define the casts for A* to int and vice versa.
Note: I currently have this working as a function in the A class, but a cast-style conversion would feel more natural in my use case.
I have a use case of unions, but as many programmers I quite find it ugly to use unions. So I tried using exception handling not in the way it is meant to be. I understand that this will introduce some loss of time due to handling of exceptions. My question is : is there a clean way to do that ?
here is the code, with union, and without
//g++ 7.4.0
#include <iostream>
using namespace std;
class C{ int i ; public : C(int i):i(i){cout << "C(" << i << ")\n";} void display() const { cout << "#C(" << i << ")\n"; } };
class D{ int i ; public : D(int i):i(i){cout << "D(" << i << ")\n";} void display() const { cout << "#D(" << i << ")\n"; } };
class E{ int i ; public : E(int i):i(i){cout << "E(" << i << ")\n";} void display() const { cout << "#E(" << i << ")\n"; } };
struct CDE { enum {C_t,D_t,E_t} kind; union { C c; D d; E e; }; CDE(){} };
CDE f(int i){
CDE res;
if( i==1 ) { res.kind = CDE::C_t; res.c = C(1); return res; }
if( i==2 ) { res.kind = CDE::D_t; res.d = D(2); return res; }
res.kind = CDE::E_t; res.e = E(i); return res;
}
void g(int i){
if( i==1 ) throw C(1);
if( i==2 ) throw D(2);
throw E(i);
}
int main(){
cout << "/** trace\n\nusing union\n";{
CDE res = f(1);
if (res.kind==CDE::C_t){ res.c.display(); }
if (res.kind==CDE::D_t){ res.d.display(); }
if (res.kind==CDE::E_t){ res.e.display(); }
}cout << "\nusing exceptions\n";{
try{
g(1);
}
catch(const C& c){ c.display(); }
catch(const D& d){ d.display(); }
catch(const E& e){ e.display(); }
}cout << "\nstop\n*/\n";
}
and here it the (obvious) trace I get
/** trace
using union
C(1)
#C(1)
using exceptions
C(1)
#C(1)
stop
*/
I'd strongly suggest against using exception for this, it's error-prone, and not what they are meant for.
One of the issue would be extensibility. Using exception, say you add one type, you have to be sure you've add it to your try-catch statement. Moreover, it's a bad habit, because it break the usual code flow. (say you add something after g(), it will never be called.
Another issue is that if there are actual exception, you would have logic mixed with error handling in the same catch block, which would then become harder to read. Or you might have code throwing an exception while an exception was already thrown, which would stop the execution altogether.
If you want to use union, you could use std::variant, or use a switch statement on your enum (which is better than using ifs one after the other.)
However, in C++, and most Object Oriented language, there is a better way to achieve what you want here, using inheritance:
class C{ int i ; public : C(int i):i(i){cout << "C(" << i << ")\n";} void display() const { cout << "#C(" << i << ")\n"; } };
class D{ int i ; public : D(int i):i(i){cout << "D(" << i << ")\n";} void display() const { cout << "#D(" << i << ")\n"; } };
class E{ int i ; public : E(int i):i(i){cout << "E(" << i << ")\n";} void display() const { cout << "#E(" << i << ")\n"; } };
In your code here, we can see that all these classes have a common interface (understand here, a common "shape", they all have a void display() const method.
We could generalize all these class as the "same" as this one (at least if the logic inside their method is ignored)
class displayable {
public:
void display() const;
};
Now, this will be a common "type". However, we want all three class to be able to either implement, or override the function display. let's change this:
class i_displayable {
public:
virtual ~i_displayable(){}
virtual void display() const = 0;
};
class displayable {
public:
virtual ~displayable() {}
virtual void display() { std::cout << "displayable with default implementation" << std::endl;}
};
So, what is the differences between those two:
i_displayable declare display as a pure virtual member. What that mean is that any class inheriting from i_displayable will have to implement display()
displayable declare display() as a virtual member, and provide an implementation. This will allow inheriting class to override the function.
I'll get to why both declare a virtual destructor in an instant.
Let's rewrite class C for now.
class C : public displayable {
int i;
public:
C(int i): i(i) { std::cout << "C(" << i >> ")" << std::endl;}
virtual ~C(){}
void display() const override {
std::cout << "#C(" << i << ")" << std::endl;
}
}
So, we've override the display function (the override keyword is optionnal), and we've said that C inherits from displayable publicly.
What this means is that we can now consider any pointer to a class C instance as a pointer to a displayable instance. As the function display is marked as virtual, when using a pointer do displayable, the function from C will be called, if it exists, and the one in displayable will be called if it does not.
That actually the reason behind making the destructor virtual. You don't want do destruct a displayable, but the actual instance (C in our case)
Now, let's say you've done this on C, D and E, your calling code can be rewritten as:
std::shared_ptr<displayable> f(int i){
std::shared_ptr<displayable> res;
if( i==1 ) { res = std::make_shared<C>(1); }
else if( i==2 ) { res = std::make_shared<D>(2); }
else { res = std::make_shared<E>(i);
return res;
}
int main(){
cout << "/** trace\n\nusing union\n";{
std::shared_ptr<displayable> res = f(1);
res->display();
}
}
Using Try Catch based Exceptional Handling seems coding-friendly in most cases
There are no conditional statements needed for run time exception handling using try-catch like your code shows. I would personally use Exceptions using Try Catch as you did.
try{
g(1);
}
catch(const C& c){ c.display(); }
catch(const D& d){ d.display(); }
catch(const E& e){ e.display(); }
I got this code:
Edit: The full code:
#include <iostream>
using namespace std;
class A {
public:
A() {}
A(const A& a) {
cout << "A copy ctor" << endl;
}
virtual ~A() {
cout << "A dtor" << endl;
}
virtual void type() const {
cout << "This is A" << endl;
}
};
class B: public A {
public:
B(){}
virtual ~B() {
cout << "B dtor" << endl;
}
void type() const override {
cout << "This is B" << endl;
}
};
A f(A a) {
a.type();
return a;
}
const A& g(const A& a) {
a.type();
return a;
}
int main() {
A* pa = new B();
cout << "applying function f:" << endl;
f(*pa).type();
cout << "applying function g:" << endl;
g(*pa).type();
delete pa;
return 0;
}
I noticed when debugging the code that after making and passing a copy of *pa to f and ending the function the destructor of the copy (*pa) that was passed to f is not called.
Only when type() ended (the same line) both the copies (I assume) were erased by the destructors
I was sure that when ending the function a destructor will be called and erase the current copy which did not happened in this case. I would like to get an explanation to the order in which the constructors and desturctors are being called in the code (I am not very knowledgeable about the order when methods are involved and I could not find much about it online).
thank you.
When you do f(*pa).type();, the Copy Constructor of A is called with an A object, so it will create an A to pass into your f function. When f returns, it is a different A being returned, since it's not by ref, however, it is NOT immediately destroyed, and instead uses copy-elision to stick around until after the .type() is called.
After that point, the destructor of both the temporary object passed into f, and the temporary object return by f are destroyed, so ~A() gets called twice.
The following test code seems to indicate that if a class has two abstract base classes with common pure virtual methods, then these methods are "shared" in the derived class.
#include <iostream>
#include <string>
using namespace std;
struct A
{
virtual string do_a() const = 0;
virtual void set_foo(int x) = 0;
virtual int get_foo() const = 0;
virtual ~A() {}
};
struct B
{
virtual string do_b() const = 0;
virtual void set_foo(int x) = 0;
virtual int get_foo() const = 0;
virtual ~B() {}
};
struct C : public A, public B
{
C() : foo(0) {}
string do_a() const { return "A"; }
string do_b() const { return "B"; }
void set_foo(int x) { foo = x; }
int get_foo() const { return foo; }
int foo;
};
int main()
{
C c;
A& a = c;
B& b = c;
c.set_foo(1);
cout << a.do_a() << a.get_foo() << endl;
cout << b.do_b() << b.get_foo() << endl;
cout << c.do_a() << c.do_b() << c.get_foo() << endl;
a.set_foo(2);
cout << a.do_a() << a.get_foo() << endl;
cout << b.do_b() << b.get_foo() << endl;
cout << c.do_a() << c.do_b() << c.get_foo() << endl;
b.set_foo(3);
cout << a.do_a() << a.get_foo() << endl;
cout << b.do_b() << b.get_foo() << endl;
cout << c.do_a() << c.do_b() << c.get_foo() << endl;
}
This code compiles cleanly in g++ 4.1.2 (admittedly old), using -std=c++98 -pedantic -Wall -Wextra -Werror. The output is:
A1
B1
AB1
A2
B2
AB2
A3
B3
AB3
This is what I desire, but I question whether this works generally, or only "by accident." Fundamentally, this is my question: can I depend on this behavior, or should I always inherit from a virtual base class for this type of scenario?
Don't make it harder than it is. A function with the same signature as a virtual function in a base class overrides the base version. Doesn't matter how many bases you have, or whether another base has a virtual function with the same signature. So, yes, this works.