First of all sorry for the title being confusing. Here's my OOP setup. I have base class Base, and two pure virtual functions add and multi. Then I have derived classes D1 and D2 and I implement the add and multi functions. I want to have a template function, that can have the flexibility that can switch between D1 D2 and calling add or multi functions. I googled around and someone people saying I should use function pointers but some others say it does not work with pure virtual functions.
class Base
{ double data; //data member
Base(double d):data(d){};
virtual double add() = 0;
virtual double multi() = 0;
}
class D1::public Base
{ D1(double d): Base(d) {}; //calling base class constructor
double add() {return data+1;} ;
double multi() {return data*2;} ;
}
class D2::public Base
{ D2(double d): Base(d) {}; //calling base class constructor
double add() {return data+3;} ;
double multi() {return data*4;} ;
}
//now I want to have a template function that give me flexibility to construct D1 or D2 and calling add or multi.
template <typename T, typename F>
void testFun(double num)
{ T tmp(num); //create object either D1 or D2;
cout << T->F() << endl; //calling either add or multi;
}
int main()
{ testFun<D1, D1.add()>(double x = 5);
//i know passing in D1.add() is wrong i don't know how to fix, hopefully you know what I am trying to achieve
return 0;}
Any help will be appreciated. Thank you guys.
There's nothing about virtual member functions that makes pointers to member functions not work. You can invoke a pointer to a pure virtual function if the object being invoked on is a pointer/reference to an object that has an actual implementation.
It looks like you're getting tripped up on the syntax of exactly how to pass a pointer-to-member-function in the first place.
Also note that virtual dispatch wouldn't even be used here since the type of object being used is known at compile time.
template <typename T>
void testFun(double num, double (T::*fn)())
{
T tmp(num);
std::cout << (tmp.*fn)() << std::endl;
}
Here, fn is a pointer to a member function of T that accepts no arguments and returns a double value. You can invoke it like so:
testFun<D1>(5, &D1::add);
Note some other errors with the example code you've given:
You specify base types with :: when you should use :. For example: class D1 : public Base.
You use class but never specify an access modifier, which means all members are implicitly private. For the purposes of the demo, changing them to struct (which defaults to public access) fixes this.
You need a semicolon after a class/struct definition.
Here is a demo of the working code.
Just for the sake of completeness, here is a demo showing that you can use a pointer to a pure-virtual member function to invoke on a reference/pointer to a derived type. The code has to be adjusted to use a D1 or D2 object through a reference of Base for the dispatch to be dynamic. This example looks like:
template <typename T>
void testFun(double num, double (Base::*fn)())
{
T tmpConcrete(num);
Base & tmp = tmpConcrete;
std::cout << (tmp.*fn)() << std::endl;
}
int main() {
testFun<D1>(5, &Base::add);
}
(Of course, here it's a bit silly to use a pointer to a Base member when the generic code knows what T is, but it proves the point that it's possible.)
Related
Is it possible to acces a member of a derived class using a pointer to the base class?
// Example program
#include <iostream>
#include <vector>
#include <memory>
#include <string>
class A {
public:
std::string x = "this is the wrong x\n";
};
template <class T>
class B : public A {
public:
T x;
};
int main()
{
std::vector<std::unique_ptr<A>> vector;
auto i = std::make_unique<B<int>>();
i->x = 6;
vector.push_back(std::move(i));
for(auto &element : vector){
std::cout << element->x;
}
}
Here I'm always getting the output from class A. I cannot typecast it because I don't know whether the element is of type A or type B in advance. Is there a proper way to do this?
The proper way would be to make a virtual function to perform the task like printing.
class A {
public:
std::string x = "this is the wrong x\n";
virtual ~A() = default;
virtual void print() const { std::cout << x; }
};
template <class T>
class B : public A {
public:
T x;
virtual void print() const override { std::cout << x; }
};
int main()
{
std::vector<std::unique_ptr<A>> vector;
auto i = std::make_unique<B<int>>();
i->x = 6;
vector.push_back(std::move(i));
for(auto &element : vector){
element->print();
}
}
If you have a pointer to a base class, you can only access things defined on that base class (without typecasting). For all the compiler knows, it is an instance of the base class and has nothing else.
Polymorphic behavior involves using virtual functions - derived classes can change which function is called when invoking a virtual function of the base class. Note that this mechanism does not exist for members (what would you change about a member? There's only the type, and changing that in a derived class makes no sense). So the only meaningful thing you can do with pointers to base classes that should have customized behavior is to call their virtual functions.
Now, you could think "ok, I'll just make access to x go through a virtual function", but the problem here is that you must specify the involved types when you declare the virtual function in the base class already. That makes sense: The compiler needs to know which types a function involves, even a virtual one. You may only pass and return different types in the overriding functions if they are "compatible" - see covariance and contravariance for more information.
So unless all your T are covariant, virtual functions cannot help you either.
The core flaw with your concept is that you want to have some type (i.e. element->x) in a non-templated function depend on the dynamic type of some object (i.e. element). That is impossible because the compiler must know the type of each expression at compile-time. So you must approach your problem differently.
Consider the following class definitions:
class foo {
virtual absl::Span<const Input *const> GetInputs() const = 0;
virtual absl::Span<Input *const> GetInputs() {
auto mutable_inputs = GetMutableInputs();
return absl::MakeSpan(mutable_inputs.begin(), mutable_inputs.end());
}
}
class bar : public foo {
absl::Span<const Input *const> GetInputs() const override {
return absl::MakeConstSpan(inputs_);
}
}
When calling bar.GetInputs() it seems like the only implementation found is the the one that returns a span of constant inputs. If I have an instance of bar, and want to create a span of non-const inputs, then I must cast bar to foo, and then call GetInputs.
If I cast bar to foo, then call GetInputs, I am then able to assign the result to a span of non-const inputs. Why does the compiler fail to identify the inherited non-const method with the correct return type? Is there a way to make the subclass identify that method?
In other words, is there a way to make the following code compile:
absl::Span<Input *const> tmp = bar.GetInputs()
If I understand your question, it has nothing to do with virtual functions or "precedence" of const, but is plain old "name hiding".
#include <iostream>
class Base {
public:
virtual void f(int) { std::cout << "Base(int)\n"; }
virtual void f(double) { std::cout << "Base(double)\n"; }
};
class Derived : public Base {
public:
virtual void f(double) { std::cout << "Derived(double)\n"; }
};
int main() {
Derived d;
int x=0;
d.f(x);
}
output: Derived(double)
The issue is, name lookup doesn't work the way it seems you expect.
For a given scope, it searches for names to build an overload set. Within the context of Derived, there is only one f(), so when it's found, the compiler stops searching further for more overloads.
It finds Derived(double) and that's the entire overload set, and so it is selected. When you cast your derived class to a reference to the base, and then call something, both functions (declared in the base) are considered, and overload resolution selects the best match.
Now, normally, for polymorphic types you are working with the objects in terms of pointers/references to the base, so it's not an issue. But if you are calling directly on the derived class (perhaps from inside a member of derived?) then it'll have this issue of the derived declaration hiding the base names.
To make the base names visible in the derived class, it's easy:
class Derived : public Base {
public:
using base::f; // <<<<<<<< just add this
virtual void f(double) { std::cout << "Derived(double)\n"; }
};
you should add
using foo::GetInputs;
in bar class to expose the base class function.
you will be able to call the base class function if the object is non-const
I have a derived class where I want one of the functions to override its version in the base class, but have a different signature.
Simple example:
#include "stdio.h"
bool use_foo = false;
class Foo {
public:
virtual int func(double x) { printf ("%f in Foo!\n", x); }
};
class Bar : public Foo {
public:
int func(short x) { printf ("%d in Bar!\n", x); }
};
int main () {
Foo* A;
if (use_foo)
A = new Foo;
else
A = new Bar;
A->func(2);
return 0;
}
The above code would call the base class copy even though A was allocated as the derived class:
> g++ test.cpp -o test -O3 && ./test
2.000000 in Foo!
Because (as far as my understanding goes) the argument can be converted to match the base class signature, and the derived class doesn't override it because of this difference (but wouldn't it hide it in that case?). If I change the base class function to have short as argument as well, the derived class does manage to override it.
Is there a simple way to convince the call to use the correct function based on the pointer? I could add another function like this:
class Bar : public Foo {
public:
int func2(short x) { printf ("%d in Bar!\n", x); }
int func(double x) { func2(x); }
};
But then I would convert the arguments all the time (short->double->short), and this function is performance critical. Is there a better way?
These function signatures are not identical:
virtual int func(double x) {...} // base class
int func(short x) {...} // derived class
One uses double parameter, the other uses short. For overriding to occur several conditions must be met. Identical parameter types of the base and derived functions being one of them. Bellow is the excerpt from the "Modern Effective C++" book by Scott Meyers on all the requirements:
• The base class function must be virtual.
• The base and derived
function names must be identical (except in the case of destructors).
• The parameter types of the base and derived functions must be
identical.
• The constness of the base and derived functions must be
identical.
• The return types and exception specifications of the base
and derived functions must be compatible.
Alternatively, make the signatures the same and perform the casting inside a derived function body:
int func(double x) override {
short temp = static_cast<short>(x);
// ...
}
What sense does this make anyway? The reason you use a virtual function is that the caller should only be required to know the base class, and thus only the base-class signature.
In other words, code which has, say, a Foo& or a Foo* or a std::unique_ptr<Foo>, only knows about the double version of your function anyway. It will pass a double when it calls func, because what else should it do?
Perhaps what you really want to do is the subclass implementation of the function to convert the double to a short. Here's an example for that, which also gets rid of the printf in favour of a type-safe C++ stream:
class Bar : public Foo {
public:
int func(double x) { std::cout << static_cast<short>(x) << " in Bar!\n"; }
};
Note that since C++11, you are encouraged to use override to mark overriding functions.
and this function is performance critical.
Should a performance-critical function be virtual at all?
Have you actually measured the speed? Is there a noticeable delay? Or are computers too fast anyway?
Here is an abstraction of my problem.
I want to develop something like this.
class Base {
}
template<typename T>
class TypedBase : Base {
f(const T& input);
}
Now I Want to access the "family" of classes TypedBase via a base pointer and call f.
Something like this
Base* base_ptr;
if (condition) {
base_ptr = new TypedBase<double>();
} else {
base_ptr = new TypedBase<int>();
}
// Int and double are just examples to get the idea
// Then I Want to call
base_ptr->f(4);
This won't compile.
I tried to add an empty virtual function f() to base hoping that vtable would take care of calling the right f() vs. f(T& input) at run time but again didn't work like:
class Base {
virtual f() = 0;
}
So how do you do that? in general I want to have a pointer to a generic TypedBase that allows me to call f(...) via a generic pointer to the family. Any thoughts?
Of course I could do this:
class Base {
// Repeat for every typename
virtual f(int& x) = 0;
virtual f(double& x) = 0;
}
and then each TypedBase will only implements one of them thus I will still get type safety at run time without doing dynamic checking myself in the code. However, If I have N functions to call and M types to work with, then I will have to add M*N abstract functions to the Base class. Any better solution?
You must static_cast (if you know the real type) or dynamic_cast (if you need to check if cast succeeded) the base pointer to right class. If you know what you are passing to method, casting to type that takes that argument should not be a problem. Also casting should work in a template method with right template type.
Does following compile?
template <typename T>
void callF(Base *p, T input) {
TypedBase<T> *tp = dynamic_cast<TypedBase<T>*>(p);
if (tp) tp->f(input);
// else throw exception or call some Base method or return error or...
}
Or less safe, just do:
static_cast<TypedBase<int>*>(base_ptr)->f(1);
Here are the requirements posed by my application. I have a class A, that accepts a function pointer say cFunc, Basically in my implementation of A, I have it call cFunc multiple times.
The cFunc pointer itself should point to different functions depending upon the application. Thus for each application I create a class with the same function definition as cFunc, however I cannot assign the class's member function to this pointer
class A {
typedef double (*Def_CFunc)(std::vector<double>);
A(Def_CFunc _cFunc) { // Some implementation}
// Other Functions
};
class B { double someFunc(std::vector<double> b); };
class C { double someOtherFunc(std::vector<double> a); };
int main () {
B firstObj;
C secondObj;
// Depending upon the situation, I want to select class B or C
double (*funcPointer)(std::vector<double>) = firstObj.someFunc; // Error in this line of code
A finalObj(funcPointer);
}
So how do I make it such that any class with a member function of the given format can be used to initialize the class A?
I'm not sure what exactly your requirements are, but it looks like you want an interface (or abstract base class in C++ lingo).
If both B and C inherit from a common base class, you can pass a pointer to this base class and invoke functions on it:
class I { virtual double func(std::vector<double> a) = 0; }
class B : public I { double func(std::vector<double> a); };
class C : public I { double func(std::vector<double> a); };
You can pass an I* pointer to A and just use i->func.
Pointer to member function has different syntax than pointer to ordinary function and can only point to a method of one given class. To be able to point to methods in different classes use boost::function or if C++11 is available use std::function. These can hold any method or function of a given signature.
What you need is std::function together with either std::bind or lambda expressions (or the Boost equivalent of the first two), because member function pointers don't allow you to do that.
You can do it using std::bind + std::function. Lets write some template class wrapper, that takes any static type as input. Then use this wrapper in free function switch_obj. Usage is very simple.
typedef std::function<double(std::vector<double>)> my_foo;
template<class C>
struct switcher
{
static my_foo convert(C* obj)
{
return my_foo( std::bind(&C::someFunc,obj,std::placeholders::_1) );
}
};
template<class T>
my_foo switch_obj(T* obj)
{
return switcher<T>::convert(obj);
}
void main()
{
B firstObj;
C secondObj;
auto f = switch_obj(&firstObj);
A a(f);
}