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.
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 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.
I have problem with clone() method in the following example. I have expected that sizeof(*((*ptr1).clone())) would be the same as b1 and sizeof(*(ptr2.clone())) would be the size of c1 but they are not. They are sizeof(a1). What am I missing?
Here is the code.
class A
{int a;
public:
virtual A * clone() {return this;}
};
class B : public A
{int b,c;
public:
B * clone() {return this;}
};
class C : public A
{int b,c,d;
public:
C * clone() {return this;}
};
int main()
{
A a1;
B b1;
C c1;
A * ptr1 = &b1;
A & ptr2 = c1;
std::cout << "sizeof(a1) = " << sizeof(a1) << '\n';
std::cout << "sizeof(b1) = " << sizeof(b1) << '\n';
std::cout << "sizeof(*(b1.clone())) = " << sizeof(*(b1.clone())) << '\n';
std::cout << "sizeof(c1) = " << sizeof(c1) << '\n';
std::cout << "sizeof(*((*ptr1).clone()))" << sizeof(*((*ptr1).clone())) << '\n';
std::cout << "sizeof(*(ptr2.clone()))" << sizeof(*(ptr2.clone())) << '\n';
return 0;
}
sizeof(*((*ptr1).clone())) is a compile time value, and expression is not executed.
so here we have sizeof(*((*std::declval<A*>()).clone())) which is sizeof(A) (we use A::clone() which returns A*).
sizeof only takes the static type of its argument into account, not the dynamic type. Thus the argument to sizeof can be an unevaluated operand, and the result of sizeof does not depend on any run-time information (such as vtables required for dynamic type information). And so the result of sizeof is always a compile-time constant expression, suitable to be used e.g. as a template argument.
See C++11: §5.3.3 [expr.sizeof]/2.
I came across a line of code and never thought it might work well. I thought the conditional operator return value and does not work with reference.
Some pseudo code:
#include <iostream>
using namespace std;
class A {
public:
A(int input) : v(input) {};
void print() const { cout << "print: " << v << " # " << this << endl; }
int v;
private:
//A A(const A&);
//A operator=(const A&);
};
class C {
public:
C(int in1, int in2): a(in1), b(in2) {}
const A& getA() { return a;}
const A& getB() { return b;}
A a;
A b;
};
int main() {
bool test = false;
C c(1,2);
cout << "A # " << &(c.getA()) << endl;
cout << "B # " << &(c.getB()) << endl;
(test ? c.getA() : c.getB()).print(); // its working
}
Can someone explain? Thx.
Your assumption about the conditional operator is wrong. The type of the expression is whatever type the expressions c.getA() and c.getB() have, if they have the same type, and if they denote lvalues, then so does the entire expression. (The exact rules are in §5.16 of the C++ standard.)
You can even do this:
(condition? a: b) = value;
to conditionally set either a or b to value. Note that this is C++-specific; in C, the conditional operator does not denote an lvalue.
The code below introduces a class C. The class has constructor, copy constructor, operator= and one member. How can I get the address of the object created by C(2) in the function main()?
#include <iostream>
class C
{
public:
int a;
C(const C &other)
{
std::cout << "Copy Constructor:" << a << std::endl;
}
C(int a)
{
this->a = a;
std::cout << "Constructor:" << a << std::endl;
}
C &operator=(const C &other)
{
std::cout << "operator=:this.a = " << a << " | other.a = " << other.a << std::endl;
a = other.a;
return *this;
}
~C()
{
std::cout << "Destructor:" << a << std::endl;
}
};
int main()
{
C a(1);
a = C(2);
}
You can't. You are forbidden from taking addresses of temporaries. They will go out of scope very quickly, leaving you with an invalid address.
You could use a helper function to write the address somewhere before the object goes out of scope:
template <typename T>
T const & store_possibly_invalid_address(T const & t, T const *& p)
{
p = &t;
return t;
}
int main()
{
C a(1);
C const * invalid_address;
a = store_possibly_invalid_address(C(2), invalid_address);
// The temporary is out of scope, but you can see where it was.
// Don't dereference the pointer.
}
That could be educational, to discover where the compiler chooses to put temporaries. It has no purpose in any real code, though.
The only way is with some collaboration inside the class; the
constructor has the address (the this pointer), and can put it
somewhere where you can get at it later. I'd recommend against it,
though, since the object won't live long enough for you to do much with
it. (On the other hand, it's sometimes useful for debugging to output
it.)