Consider the following. Class A has a function pointer as a member and accepts a function in its constructor to pass to this member. In a separate file, I have a class B that contains a pointer to class A as a member, and class B also has as a member the function I want to pass to class A.
Below is an example and the errors I receive. What's the standard method of doing something like this?
A.h:
class A {
private:
int (*func)(int);
public:
A(int (*func_)(int));
};
A::A(int (*func_)(int)) : func(func_) {}
B.h:
#include "A.h" // Why can't I forward declare A instead?
class B {
private:
A *A_ptr;
int function(int); // some function
public:
B();
~B();
};
int B::function(int n) {
return n+2; // some return value
}
B::B() {
A_ptr = new A(function);
}
B::~B() {
delete A_ptr;
}
main.cpp:
#include "B.h"
int main() {
B b;
}
Errors I get:
B.h: In constructor ‘B::B()’:
B.h:18:25: error: no matching function for call to ‘A::A(<unresolved overloaded function type>)’
B.h:18:25: note: candidates are:
A.h:9:1: note: A::A(int (*)(int))
A.h:9:1: note: no known conversion for argument 1 from ‘<unresolved overloaded function type>’ to ‘int (*)(int)’
A.h:1:7: note: A::A(const A&)
A.h:1:7: note: no known conversion for argument 1 from ‘<unresolved overloaded function type>’ to ‘const A&’
To answer your question regarding "What's the standard method of doing something like this" I'll assume you mean passing member functions and/or general function pointers around and executing them with some data. Some popular implementations which provide this ability are:
FastDelegate
std::function
boost::function
It really comes down to preference and library choice. Personally, I've used FastDelegate most of the time and then std::function after that.
All the links I posted should have tutorial information to get you up and running and show you how to properly pass and store member functions and/or general function pointers with ease.
Here's an example of using a FastDelegate with your example:
class A
{
public:
// [1] This creates a delegate type. Can used for any function,
// class function, static function, that takes one int
// and has a return type of an int.
typedef FastDelegate1< int, int > Delegate;
// [2] Pass the delegate into 'A' and save a copy of it.
A( const Delegate& delegate ) : _delegate( delegate ) { };
void execute()
{
// [7]
// Result should be 10!
int result = _delegate( 8 );
}
private:
// [3] Storage to save the Delegate in A.
Delegate _delegate;
};
class B
{
public:
B()
{
// [4] Create the delegate
A::Delegate bDelegate;
bDelegate.bind( this, &B::function );
// [5] Create 'A' passing in the delegate.
_aPtr = new A( bDelegate );
// [6] Test it out!! :)
// This causes `A` to execute the Delegate which calls B::function.
_aPtr->execute();
}
~B()
{
delete _aPtr;
}
int function( int n )
{
return n+2;
}
private:
A* _aPtr;
};
Related
how can I assign an inherited method to an object?
, can you explain to me what is wrong with my code?
I am a newbie, so I would like to know if there is a better way to do it
int main(){
CalculateData data;
data = data.ReadData(data);//does not let me assign data to the method??
}
Rest of the code
#include<string>#include<fstream>#include<iostream>#include<vector>using namespace std;
class File//base class
{
private:
double Size;
public:
vector <double>values;
double GetSize();
void SetSize(double size);
File ReadData(File data);
};
class CalculateData :public File {//inherent from file class
public:
std::vector <double> value;
}
File File::ReadData(File file) {//method of File class
{std::fstream File("Data.txt", std::ios_base::in);
double a;
int counter = 0;
while (File >> a)
{
//printf("%f ", a);
file.values.push_back(a);
counter++;
}
file.SetSize(counter);
cout << "size is " << file.GetSize() << endl;
File.close();
}
return file;
}
Frankly, it is hard to help, because the error is just a consequence of a flawed approach. I'll use an example simpler than yours that has most of the same issues:
#include <iostream>
struct Base {
int value;
Base read(Base b) {
b.value = 42;
return b;
};
};
struct Derived : Base{
int values;
};
int main() {
Derived d;
d = d.read(d);
}
The immediate problem is the compiler error:
<source>: In function 'int main()':
<source>:17:17: error: no match for 'operator=' (operand types are 'Derived' and 'Base')
17 | d = d.read(d);
| ^
<source>:11:8: note: candidate: 'constexpr Derived& Derived::operator=(const Derived&)'
11 | struct Derived : Base{
| ^~~~~~~
<source>:11:8: note: no known conversion for argument 1 from 'Base' to 'const Derived&'
<source>:11:8: note: candidate: 'constexpr Derived& Derived::operator=(Derived&&)'
<source>:11:8: note: no known conversion for argument 1 from 'Base' to 'Derived&&'
d is a Derived and read returns a Base. They are different types, you cannot assign them to each other unless you provide some conversion between them.
However, it does not make sense that read takes a Base as argument (by value) and returns that just to let the caller assign it to the object they called the method on. If the method is intended to modify the current object then it should do so directly:
void read() {
value = 42;
}
There is absolutely no need to pass a Base as argument, which will be copied anyhow, because you pass it by value.
The next thing that is fishy in the code is that Derived has another member which is similar named as the one of Base but unused. Derived already does inherit the value member from Base. It does not need another values member.
Last but not least, initialization of members should take place in the initializer list of the constructor (if not in-class initializers are used). If initialization is complicated a static method can be used. Hence:
struct Base {
int value;
Base() : value( read_input() ) {}
static int read_input() {
return 42;
}
};
struct Derived : Base {};
int main() {
Derived d;
}
This code does the same as the above. As it is not clear what the purpose of Derived is, it can be removed.
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.
I have two classes, Foo and Bar. Class Foo contains an instance of class Bar called b and class Bar needs to access the member function FooFunc of class Foo. Function FooFunc performs some arithmetic, but for now I just want to try to pass it but I can't seem to make the following MWE (named scratch.cpp) work:
#include <iostream>
class Foo; // forward declaration
class Bar
{
public:
Bar() {}
void BarFunc(double (Foo::*func)(double))
{
std::cout << "In BarFunc \n";
}
};
class Foo // must be declared after Bar, else incomplete type
{
public:
Foo() {}
Bar b;
double FooFunc(double x)
{
return x + 1;
}
void CallBarFunc()
{
b.BarFunc(FooFunc); // error occurs here
}
};
int main()
{
Foo f;
f.CallBarFunc();
}
The error I get is
scratch.cpp:27:22: error: no matching function for call to ‘Bar::BarFunc(<unresolved overloaded function type>)’
scratch.cpp:27:22: note: candidate is:
scratch.cpp:9:8: note: void Bar::BarFunc(double (Foo::*)(double))
scratch.cpp:9:8: note: no known conversion for argument 1 from ‘<unresolved overloaded function type>’ to ‘double (Foo::*)(double)’
Unlike non-member functions, which decay to a function pointer, non-static member functions don't decay to a pointer.
Instead of:
b.BarFunc(FooFunc);
Use:
b.BarFunc(&Foo::FooFunc);
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 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 {
...
};