Assign base class pointer to derived class without using dynamic cast - c++

In this given piece of code,i am trying to assign base class pointer to derived class pointer (downcasting) without using dynamic cast.Using help of assignment operator.
#include<iostream>
using namespace std;
class A
{
int i;
public:
A& operator =( const A& b)
{
i = b.i;
return *this ;
}
};
class B:public A
{
int j;
public:
B& operator =( const B& c)
{
A::operator=(c);
j=c.j;
return *this ;
}
};
int main()
{
A *a;
B *b;
b=a;
return 0;
}
It shows error: invalid conversion of A* to B*.

You have to cast it by dynamic_cast or static_cast(be careful of UB in this case) ...
In C++, run-time type checking is implemented through dynamic_cast.
Compile-time downcasting is implemented by static_cast, but this
operation performs no type check. If it is used improperly, it could
produce undefined behavior [1].
and your assignment operators will not help.

Related

Return class object with member variable

Why the function test() works even I'm not returning a Base class ? What happens with the compilation ? Can someone explain me ?
#include <iostream>
class Base {
public:
Base(){}
Base(int val): _val(val){};
~Base(){};
Base test(int n){
return (n);
}
int &operator *() { return (_val); };
private:
int _val;
};
int main()
{
Base base;
Base a;
a = base.test(42);
std::cout << *a << std::endl;
return (0);
}
You declared a constructor that takes in an int, and you declared that test(int n) should always return a Base class. The compiler knows that in order to create a Base object you need either nothing (default constructor) or an int, so it creates an object using the constructor that takes an int an returns that.
If you wanted to, you could be explicit about it and do something like the following and get the exact same behaviour:
Base test(int n){
return Base(n);
}
In short, n is implicitly cast to a Base object, as you declared a constructor that requires only an int.

Implicit conversion insists on using private function

I have a class that has a conversion operator to int& that I want to hide. I created a derived class that only offers a conversion to int and made the conversion to int& private. But I still cannot make the int conversion to be used, either the compiler tells me that the conversion is ambiguous, or insists to use the int& conversion and tells me it is inaccessible. How do I make this work?
struct Base {
int value;
operator int&() { return value; }
};
struct Derived : Base {
operator int() { return operator int&(); }
private:
using Base::operator int&;
};
int main() {
int p = Derived();
}
P.S. The compiler uses gcc 9.3.0, and the real case is the wrapping of XmlRpc::XmlRpcValue class from ROS to handle probable conversion from double XmlRpcValue type to int or int XmlRpcValue type to double.
I could not find a way through inheritance. But if containment is an option (Derived has a Base instead of is a), it is much simpler:
struct Base {
int value;
operator int&() { return value; }
};
struct Derived{
Base b;
operator int() { return b.operator int&(); }
};
int main() {
int p = Derived();
}
The main drawback is that you will have to use explicit delegation for the methods/members you want to offer in Derived

How to make implicit conversion constructor call over 2 class in C++?

Here is the test code:
class A
{
public:
A(const int& i){}
};
class B
{
public:
B(const A& a) {};
};
int main()
{
B b = 1;
return 0;
}
It comes to error: "No viable conversion from int to B".
It's obviously that int can be converted to B through being converted to A. But it seems that C++ does not search the constructor inherited tree.
Note that B is not inherited from A.
Is there any way to make it possible without adding a int constructor for B manually?

Pre and post increment operators in different classes

I want to create traits that overload operators, to avoid code duplication. But when I try to put pre and post increment operators in different classes the compiler gives me an error: "operator ++ is ambiguous" Code:
class A
{
public:
A& operator++(){return *this;}
};
class B
{
public:
B operator++(int){return *this;}
};
class C:public A, public B
{
};
int main()
{
C c;
c++;
++c;
}
In my case it is possible to inherit B from A, but then the compiler can't find the post-increment operator. Why does this happen, and what is the correct way?
GCC rejects the code, because it first performs name lookup without considering the argument lists, and the name is found in two base classes. Clang accepts the code, but this is caused by a bug.
The solution is to add using and create a separate class which inherits from A and B, and then inherit C from that class.
class A
{
public:
A& operator++(){return *this;}
};
class B
{
public:
B operator++(int){return *this;}
};
class AAndB:public A, public B
{
public:
using A::operator++;
using B::operator++;
};
class C:public AAndB
{
};
int main()
{
C c;
c++;
++c;
}

Typecast operator overloading problem

For example i have two classes A and B, such that for two objects a and b, i want to be able to do :
A a;
B b;
a = b;
b = a;
for this i have overloaded the = operator, and the typecast operators as:
class A{
-snip-
operator B()const { return B(pVarA); }
};
class B{
-snip-
operator A()const { return A(pVarB); }
};
but when i try to compile this code, gcc throws the error :
error: expected type-specifier before 'B'
for the line: operator B()const { return B(pVarA);}
my guess is, this is due to a chicken and egg problem as class B is defined after class A.
Is there a way to circumvent this while still using the overloaded typecast operators. And if not, then what might be the best way to achieve my goals.
Any help will be appreciated. Thanks in advance.
Try forward declaring then supplying the actual function definitions later on:
class B;
class A{
-snip-
operator B()const;
};
class B{
-snip-
operator A()const;
};
inline A::operator B() const
{
return B(pVarA);
}
inline B::operator A() const
{
return A(pVarB);
}
This should work:
class B;
class A{
operator B()const;
};
class B{
operator A()const { return A(pVarB); }
};
A::operator B() const { return B(pVarA); }