I have a class C that can be converted to class A and a function that takes an A* as an argument. I want to call it with a C*, but I can't seem to get a conversion constructor to work. I get: error: cannot convert ‘C*’ to ‘A*’ for argument ‘1’ to ‘void doSomething(A*)’. What am I doing wrong?
class C {
};
class A {
public:
A(C* obj) {}
};
void doSomething(A* object);
int main()
{
C* object = new C();
doSomething(object);
}
Conversion constructors can only be defined for user defined types, in your case A. However, they do not apply to fundamental types as pointers like A*.
If doSomething was taking an A const& instead (or simply an A), then the conversion constructor would be invoked as you expect.
If you main requirement is to be able to call the existing doSomething function, then you can do this:
int main()
{
C* object = new C();
A a(object);
doSomething(&a);
// May need to delete object here -- depends on ownership semantics.
}
You probably mean that you want C to be a subclass of A:
class C : public A {
...
};
Related
Can I pass the method as a pointer to some function that accepts the base class method pointer?
Like here, function tryit accepts two parameters with class Object. There should be polymorphism, but the compiler throws an error.
#include <iostream>
using namespace std;
class Object {
};
class Derived : public Object
{
private:
public:
void printit() {
cout << "Ok" << endl;
}
};
void tryit(Object* obj, void (Object::*fn)() ) {
(obj->*fn)();
}
int main() {
Derived d;
tryit(&d, &Derived::printit);
}
Compiler says this:
main.cc: In function ‘int main()’:
main.cc:31:15: error: cannot convert ‘void (Derived::*)()’ to ‘void (Object::*)()’
31 | tryit(&d, &Derived::printit);
| ^~~~~~~~~~~~~~~~~
| |
| void (Derived::*)()
main.cc:24:25: note: initializing argument 2 of ‘void tryit(Object*, void (Object::*)())’
24 | void tryit(Object* obj, void (Object::*fn)() ) {
| ^~~~~~~~~~~~~~~~~~~~
I don't want to use virtual methods in Object class, because I want to be able to call function with various names.
This works:
typedef void (Object::*memfn)();
tryit(&d, (memfn) &Derived::printit);
But why this is not converted implicitly, why do I need to cast it manually?
Unfortunately, polymorphism doesn't work this way. Member-pointers of derived classes are not implicitly convertible to member-pointers of parent classes. Only pointers (and references) to derived class objects are implicitly convertible to pointers to parent class objects.
You can cast your pointer, and make compiler happy:
int main() {
Derived d;
tryit(&d, static_cast<void (Object::*)()>(&Derived::printit));
}
Thanks to #StoryTeller-UnslanderMonica for digging, there seems to be an explicit blessing in Standard:
https://timsong-cpp.github.io/cppwp/n4868/expr.static.cast#12
Using virtual is the legal and safe way to handle this for polymorphic types. Your claim that you don't want to use virtual because you "want to be able to call function with various names" makes no sense.
But, if you really don't want to use virtual then consider making tryit() a template function instead, eg:
template<typename T>
void tryit(T* obj, void (T::*fn)() ) {
(obj->*fn)();
}
int main() {
Derived d;
tryit(&d, &Derived::printit);
}
Alternatively:
template<typename Callable>
void tryit(Callable fn) {
fn();
}
int main() {
Derived d;
tryit([&](){ d.printit(); });
}
Or, you can use std::function without a template, eg:
void tryit(std::function<void()> fn) {
fn();
}
int main() {
Derived d;
tryit([&](){ d.printit(); });
}
But why this is not converted implicitly, why do I need to cast it manually?
Because it's one of those conversions where you have to tell the compiler you posses extra knowledge that guarantees it's safe. Take object pointers for instance:
struct A { int x; };
struct B : A { char c; };
A *pa = new B();
auto pb = static_cast<B*>(pa);
Converting a B* to an A* is implicit. It's an unambiguous base class. The compiler knows there is an A object in that B and can just go ahead with it. But the converse is not true, you must cast it (employing your extra knowledge) to let it know that that A* is really pointing at a B*.
Pointers to members are the same in a way.
int B::* pmb = &A::x;
auto pma = static_cast<char A::*>(&B::c);
pa->*pma = 'c';
Obtaining a pointer to a member of B from a pointer to a member of A is an implicit conversion. The same knowledge about B containing an A (and therefore the member x) is available to the compiler. But it cannot assume the converse willy-nilly. What if the object pointer pa is not really pointing at a B? Accessing that "member of B" would be disastrous then.
By the same reasoning as before, you need a cast to let the compiler know you have extra knowledge about the actual derived object type.
First, I define two classes, which inherits from one another.
class A {
};
class B : public A {
};
Then, I declare a function that uses an std::function<void(A*)> :
void useCallback(std::function<void(A*)> myCallback);
Finally, I receive a std::function of a different (but theoretically compatible) type from somewhere else that I would like to use in my callback function:
std::function<void(B*)> thisIsAGivenFunction;
useCallback(thisIsAGivenFunction);
My compiler (clang++) refuses this because the type of thisIsAGivenFunction doesn't match the expected type. But with B inheriting from A, it would make sense for thisIsAGivenFunction to be acceptable.
Should it be? If not, why? And if it should, then what am I doing wrong?
Let's suppose that your class hierarchy is a little bigger:
struct A { int a; };
struct B : A { int b; };
struct C : A { int c; };
and you have functions like below:
void takeA(A* ptr)
{
ptr->a = 1;
}
void takeB(B* ptr)
{
ptr->b = 2;
}
Having that, we can say that takeA is callable with any instance of class derived from A (or A itself), and that takeB is callable with any instance of class B:
takeA(new A);
takeA(new B);
takeA(new C);
takeB(new B);
// takeB(new A); // error! can't convert from A* to B*
// takeB(new C); // error! can't convert from C* to B*
Now, what std::function is, it is a wrapper for callable objects. It doesn't care much about the signature of stored function object as long as that object is callable with parameters of its std::function wrapper:
std::function<void(A*)> a; // can store anything that is callable with A*
std::function<void(B*)> b; // can store anything that is callable with B*
What you are trying to do, is to convert std::function<void(B*)> to std::function<void(A*)>. In other words, you want to store callable object taking B* within wrapper class for functions taking A*. Is there an implicit conversion of A* to B*? No, there is not.
That is, one can as well call std::function<void(A*)> with a pointer to an instance of class C:
std::function<void(A*)> a = &takeA;
a(new C); // valid! C* is forwarded to takeA, takeA is callable with C*
If std::function<void(A*)> could wrap an instance of callable object taking only B*, how would you expect it to work with C*?:
std::function<void(B*)> b = &takeB;
std::function<void(A*)> a = b;
a(new C); // ooops, takeB tries to access ptr->b field, that C class doesn't have!
Fortunately, the above code does not compile.
However, doing this the opposite way is fine:
std::function<void(A*)> a = &takeA;
std::function<void(B*)> b = a;
b(new B); // ok, interface is narrowed to B*, but takeA is still callable with B*
You can't pass &Foo(Apple) when somebody may pass you a random Fruit including a Pear.
It works but in opposite direction:
struct A {};
struct B: A {};
struct X {};
struct Y: X {};
static X useCallback(std::function<X(B)> callback) {
return callback({});
}
static Y cb(A) {
return {};
}
int main() {
useCallback(cb);
}
The signature of callback declares what will be passed to it and what is to be got back. Specific callback can take less specific types if doesn't care too much about them. Similarly it can return more specific type, extra information will be stripped. Refer to covariant vs contravariant types (input/output in simplified wording).
I'd like to assign the object of type B to object of type A, but i don't know why it works with different types for the assignment?
#include <stdio.h>
class B
{
public:
B()
{
printf("B default constructor.\n");
}
};
class A
{
public:
A()
{
printf("A Default constructor.\n");
}
A(B const& b) // if add the tag "explicit" for the constructor, it will not work...
{
printf("User constructor.\n");
}
A(const A& a)
{
printf("copy-constructor.\n");
}
void get(){printf("A::get\n");}
};
int main()
{
A a = B(); // What's the meaning to assign object of type B to object of type A?
Why it works with above line?
How it works when do this?
a.get();
}
Every constructor that can be called with a single argument defines an implicit conversion to a class type. So the constructor:
A(B const& b)
is a conversion constructor. If this type of conversion is not useful, you've found the answer: declaring it as explicit can prevent it:
explicit A(B const& b)
I think your problem comes from thinking it is assignment. But A a = B(); is initialization. a is not first created with default constructor and then assigned to, it is directly constructed. And while I don't have the standard reference handy, if you don't have the constructor but have the assignment operator overload, that line will not compile, because it is not assignemnt, it needs the right constructor. To have assignment, try
A a;
a = B(); // actually assigns A(B()) implicitly if no operator= overload
If all data members of a class can be assigned, then objects of the class can be assigned, so that's why a = A(); works without adding any code.
If you want to block the implicit conversion, make the constructor explicit (example in the other answer).
We have an usual class hierarchy:
class B
{
public:
int x;
B() : x(0) {}
virtual ~B() {}
};
class D : public B
{
public:
int y;
D() : y(0) {}
};
And a function that takes one argument - reference to a base class object.
void b_set(B& b)
{
b.x = 5;
}
Then, I want to create function pointer of type void (D&) and store b_set in it. This should be valid operation, as all objects legally passed to function pointer call must be also of type B. Yet it isn't allowed.
typedef void (*fp_d_mutator)(D&);
void fp_test(D& obj)
{
fp_d_mutator fun = b_set; //invalid conversion from 'void (*)(B&)' to 'fp_d_mutator {aka void (*)(D&)}
fun(obj);
}
#include <functional>
typedef std::function<void (D&)> stdfun_d_mutator;
void stdfun_test(D& obj)
{
stdfun_d_mutator fun = b_set; //works
fun(obj);
}
So...
How is that invalid conversion?
Why is that invalid conversion?
What could break if this was allowed?
How std::function avoids the problem in the first place?
A function that takes an argument of type B& is not a function that takes an argument of type D&. While D& is convertible to B&, they are not the same type. If you could store a pointer to a function that takes B& as a pointer to D&, how would the compiler know when to convert the argument? (Note that the conversion sometimes requires adjusting a pointer)
The difference in std::function is that the calling signature (here D&) is part of the function object's type, and the called signature (here B&) is part of the internal storage. So when you apply the function objects' operator() the code that implements operator()(D&) takes care of the conversion.
I can't compile the following code using g++ 4.1.2:
#include <memory>
class A
{
public:
};
std::auto_ptr<A> GetA()
{
return std::auto_ptr<A>(new A);
}
class B
{
B(std::auto_ptr<A>& pA)
{
}
};
class C : public B
{
C() : B(GetA())
{
}
};
I get:
invalid cast of an rvalue expression of type std::auto_ptr<A> to type std::auto_ptr<A>&
The problem is I can't define a variable and pass its reference because I am inside a initialization list.
How can I do that when I am only allowed to change class C?
If you can only change C, you could do something like:
class C: public B
{
explicit C(std::auto_ptr<A>& pA) : B(pA) {}
public:
static C *GetC()
{
std::auto_ptr<A> pA = GetA();
return new C(pA);
}
};
The problem is trying to bind a non-const reference to the temporary returned by GetA. If you can assign that to a variable first, you have an lvalue and it works ok.
As Alex B says said (deleted answer), if you can change B, it would be better to take that auto_ptr argument by value; and if you can change compiler, it would be better to use unique_ptr and move semantics instead.
Depends on what B does with the passed in reference.
If B is going to take a copy of the argument, then make the argument a const &
If B is going to hold a reference to the argument then you need whatever is passed in to have a longer lifetime than the instantiation of B. (As mentioned already, the temporary created by a call to GetA() doesn't.)