I have this simple code:
#include <iostream>
using namespace std;
class GenericMove {};
class SwapMove: public GenericMove {};
class SoftConstraint {
public:
virtual int evaluate(GenericMove& gm) = 0;
};
class M1: public SoftConstraint {
public:
int evaluate(GenericMove& gm){ return 1; }
int evaluate(SwapMove& gm){ return 2; }
};
int main () {
M1 m1;
GenericMove* swapmove = new SwapMove();
cout << "Hello " << m1.evaluate(*swapmove) << endl;
return 0;
}
I would like to discern between GenericMove and SwapMove in the evaluate function of M1 , so I would like that the main prints "Hello 2".
Is there a way to distinguish that swapmove is not only a simple GenericMove but it is also SwapMove inside M1?
Is that possible in C++?
Thanks in advance!
No, this is not directly possible in C++ AFAIK, but you can use double dispatch to achieve your desired result.
class GenericMove;
class SwapMove;
class SoftConstraint {
public:
virtual int evaluate(GenericMove& move) = 0;
virtual int evaluate(SwapMove& move) = 0;
};
class M1 : public SoftConstraint {
public:
int evaluate(GenericMove& move) { return 1; }
int evaluate(SwapMove& move) { return 2; }
};
class GenericMove {
public:
virtual int evaluate(SoftConstraint& constraint) {
return constraint.evaluate(*this);
}
};
class SwapMove : public GenericMove {
public:
int evaluate(SoftConstraint& constraint) {
return constraint.evaluate(*this);
}
};
int main () {
M1 m1;
GenericMove* swapmove = new SwapMove();
std::cout << "Hello " << swapmove->evaluate(m1) << std::endl;
return 0;
}
Note that in my proposal you have to call the evaluate method of the move instance as opposed to calling the evaluate method of the constraint. But this could be changed easily.
Double dispatch exploits the fact that the static type of the this pointer is always the type to which the function using the this pointer belongs. In our example, the static type of this in GenericMove::evaluate is GenericMove*
, so the call to SoftConstraint::evaluate selects the function that takes a reference to an instance of GenericMove as its argument. On the other hand, the static type of this in SwapMove::evaluate is SwapMove*
, so the call to SoftConstraint::evaluate selects the function that takes a reference to an instance of SwapMove as its argument.
Double dispatch allows you to select a method using the type of the receiver of the call and the type of one argument.
Related
Description:
I was trying to create a class object based on the user input. I tried to store its reference with a pointer and use it at a later stage. A similar idea with the variable type late in Dart language. Is it possible to have this operation in CPP and if so, what kind of variable type should I use?
Code:
#include <iostream>
#include <vector>
using namespace std;
template <typename T>
class foo {
public:
T item;
foo(){}
};
class bar_1 {
public:
int value = 99;
void randomise();
};
class bar_2{
public:
string value = "init";
void randomise();
};
int main()
{
int i;
cin >> i;
void* ptr;
if (i > 0) {
ptr = new foo<bar_1>;
}
else {
ptr = new foo<bar_2>;
}
// maybe run the function to randomise 'value'
// ptr->item.randomise();
cout << ptr->item.value;
return 0;
}
Error:
cout << ptr->item.value;
| ^~
error: ‘void*’ is not a pointer-to-object type
Edit 1: I am not allowed to modify the class bar atm, aschepler’s #1 solution fits the best.
Edit 2: I am revisiting this problem. I found the most straightforward method is to dump using a template and convert them into a class hierarchy structure, with 'bar 1' and 'bar 2' being the offspring classes of 'foo'. So, if a pointer to class 'foo' exists in the scope, it may be assigned as a pointer to either a 'bar 1' or a 'bar 2' object.
Updated code: (class hierarchy)
#include <iostream>
using namespace std;
class foo {
public:
// common function going to be overrided by children classes
virtual void randomize() {
}
};
class bar_1: public foo {
public:
int value = 99;
// bar_1 version of randomize()
void randomize() override {
cout << "Turning int from " << value << " to a new int\n";
value++; // increment by 1
}
};
class bar_2: public foo {
public:
std::string value = "something";
// bar_2 version of randomize()
void randomize() override {
cout << "Turning string from " << value << " to a new string\n";
value = "new thing"; // diff string
}
};
int main()
{
int type = 1; // e.g type can variate from 1 to 10
foo* ptr;
switch(type)
{
case 1:
ptr = new bar_1();
break;
case 2:
ptr = new bar_2();
break;
// case 3:
// ...
default:
cout << "Invalid type\n";
break;
}
ptr->randomize();
return 0;
}
Updated code: (keep using template class)
#include <iostream>
#include <variant>
#include <optional>
using namespace std;
template <typename T>
class foo {
public:
T item; // an object either bar_1 or bar_2
foo(T _item) : item(_item) {} // constructor assigning in-class variable "item"
T getItem() // template function returning the in-class variable item
{
return item;
}
};
class bar_1 {
public:
int value = 99;
};
class bar_2{
public:
string value = "str";
};
int main()
{
int i = 0; // some value
optional<variant<foo<bar_1>, foo<bar_2>>> foo_foo;
if (i > 0) {
foo_foo = foo(bar_1());
}
if (i < 0) {
foo_foo = foo(bar_2());
}
// using visit
// if i > 0, it gives 99 as foo.item has type bar_1, which has an int value 99
// if i < 0, it gives "str" as foo.item has type bar_2, which has an string value "str"
// if i == 0, it gives 0 as the optioanl variable foo_foo contains no values
visit([](auto &_foo) { cout << _foo.getItem().value; }, *foo_foo);
return 0;
}
Definitely not in the way dynamic languages like JS and (AFAIK) Dart allow.
C++ is statically typed, so by the time you write cout << ptr->item.value in a (non-template) function, the types of item and value must be known. No way conflating unrelated types like int and string at runtime.
However, you may be able to use inheritance to achieve desired effect. A pointer to an object may always be converted to a pointer to its (accessible, i.e. public in most cases) base, and accessed like that base—but the object will retain its actual type, and all virtual methods of base will act on that type, and can be overriden:
class foo {
public:
virtual ~foo() = default; // optional but highly recommended
virtual randomize() {
// the default implementation
}
// or: virtual randomize() = 0; // if you want ALL subclasses to override it
};
class bar_1: public foo {
public:
int value = 99;
void randomize() override {
// the bar_1-specific implementation
}
};
class bar_2: public foo {
public:
std::string value = "something";
void randomize() override {
// the bar_2-specific implementation
}
};
...
foo *obj = new bar_1(); // create an object of type bar_1, but treat it as foo
obj->randomize(); // will call bar_1::randomize as obj points to an object of type bar_1
// obj->value = 42; // won’t work: value is not a member of foo
delete obj;
obj = new bar_2(); // now, create an object of type bar_2, but treat it as foo again
obj->randomize(); // will call bar_2::randomize as obj now points to an object of type bar_2
delete obj;
Or with smart pointers (highly recommended):
std::unique_ptr<foo> obj = std::make_unique<bar_1>()
// std::unique_ptr<foo> obj{new bar_1()}; // if you can’t afford C++17
obj->randomize();
obj = std::make_unique<bar_2>();
// obj.reset(new bar_2()); // if you can’t afford C++17
obj->randomize();
As comments have pointed out, you can't use a pointer to a variable declared in a block after the end of that block. You could fix this with a std::unique_ptr, or possibly std::optional.
Here are two possible solutions.
#1: A std::variant<foo<bar_1>, foo<bar_2>> can hold an object of either type, without requiring any changes to your existing classes (and without requiring any dynamic allocations). Then we can use std::visit to do things on whichever object it contains.
#include <variant>
#include <optional>
int main()
{
int i;
std::cin >> i;
std::optional<std::variant<foo<bar_1>, foo<bar_2>>> the_foo;
if (i > 0) {
the_foo = foo<bar_1>{};
}
else {
the_foo = foo<bar_2>{};
}
// run the function to randomise 'value'
std::visit([](auto &foo) { foo.item.randomise(); }, *the_foo);
std::visit([](auto &foo) { std::cout << foo.item.value; }, *the_foo);
return 0;
}
#2 If you can change the classes, notice that bar_1 and bar_2 both contain some common operations "randomise item" and "print item". So we can create an interface allowing polymorphic use of those operations without knowing the actual type. This is also more easily extensible if you add additional similar classes later.
class IBar {
public:
virtual ~IBar() = default;
virtual void print(std::ostream& os) const = 0;
virtual void randomise() = 0;
};
class bar_1 : public IBar {
public:
int value;
void print(std::ostream& os) const override
{ os << value; }
void randomise() override;
};
class bar_2 : public IBar {
public:
std::string value;
void print(std::ostream& os) const override
{ os << value; }
void randomise() override;
};
Now foo doesn't even need to be a template. It can just use an interface pointer instead of a member of the actual type:
#include <memory>
class foo {
public:
std::unique_ptr<IBar> pItem;
explicit foo(std::unique_ptr<IBar> p) : pItem(std::move(p)) {}
foo() = default;
};
int main()
{
int i;
std::cin >> i;
foo the_foo;
if (i > 0) {
the_foo.pItem = std::make_unique<foo<bar_1>>();
}
else {
the_foo.pItem = std::make_unique<foo<bar_2>>();
}
// run the function to randomise 'value'
the_foo.pItem->randomise();
the_foo.pItem->print(std::cout);
return 0;
}
I'm testing, trying to call a member function being passed as a parameter,
the member function has to be one of another class.
this is an example, which gives an error:
"pointer-to-member selection class types are incompatible ("B" and
"A")"
This is the code, what am I doing wrong?
#include <iostream>
using namespace std;
class A {
private:
public:
void fA(int x) {
cout << "hello" << endl;
}
void fB(int x) {
cout << "good bye" << endl;
}
A() {
}
};
class B {
private:
void (A:: * f)(int) = NULL;
public:
B(void (A:: * f)(int)) {
this->f = f;
}
void call() {
(this->*f)(10); //What's wrong here?
}
};
A a = A();
B b = B(&(a.fA));
B b2 = B(&(a.fB));
int main(void) {
b.call();
b2.call();
}
&(a.fA) is not legal C++ syntax. &A::fA is. As you can see, there is no object of type A anywhere of this syntax. &A::fA is just a pointer to a member function, not a pointer-to-member-together-with-an-object combo.
Now in order to call that pointer-to-member, you need an object of class A. In class B, you don't have any. You need to get one in there somehow, and call the function this way:
(a->*f)(10);
where a is a pointer to that object of class A.
Notice in this example I created a derived class pointer (Laser* pLaser = new Laser) instead of a base class pointer like (Boat* pLaser = new Laser). Is there an advantage creating a base class pointer instead? Thanks!
#include <iostream>
using namespace std;
class Boat
{
protected:
int length;
public:
int getLength() { return length; }
virtual void Model() = 0;
};
class Sailboat : public Boat
{
protected:
int mast;
public:
int getMast() { return mast; }
virtual void Boom() = 0;
};
class Laser : public Sailboat
{
public:
Laser() { mast = 19; length = 35; }
~Laser();
void Model() { cout << "Laser Classic" << endl; }
void Boom() { cout << "Boom: 14 ft" << endl; }
};
int main()
{
Laser* pLaser = new Laser;
pLaser -> Model();
cout << "Length: " << pLaser -> getLength() << "ft" << endl;
cout << "Height: " << pLaser -> getMast() << "ft" << endl;
pLaser -> Boom();
return 0;
}
Each one have a different purpose.
Child pointer
Laser* pLaser = new Laser purpose is to simply use dynamic allocation for this type, sometimes for sharing this data with other threads/processes. Usually you don't have to use it in C++, and you usually allocate this type on the stack.
Parent pointer
Boat* pLaser = new Laser This is a different story of polymorphism. If you want to store different type that implement the same interface you have to use this form (usually with smart pointers, but still same idea). For example, assume you want a container (e.g. std::vector) to include both Sailboat and Laser. Using this form you can do something like:
std::vector<Boat*> vec = {new Laser(), new Sailboat()};
for (auto &e : vec) {
std::cout << e->getLength() << std::endl;
}
As I mentioned, sometimes you have to use this form, and those times are when you have at lease one pure virtual function in you base class. In this case, you can't create an object on the stack of the base class (due to incomplete type). For exmaple:
class Base {
public:
virtual int compare(int, int) = 0;
};
class Derived : public Base {
public:
int compare(int a, int b) {
return a - b;
}
};
int main() {
//Base b; // Compilation error
Derived c; // OK
std::shared_ptr<Base> base_pointer = std::make_shared<Derived>(); // OK
return EXIT_SUCCESS;
}
Read more about:
Polymorphism C++
I'm trying to execute a function that receives a parameter, which is a reference to an abstract class, through std::async but it seems that that is not valid for some reason. On the other hand, if I replace the mentioned reference by a pointer everything works.
Why does this happen? Is it generally better to pass abstract class parameters as pointers?
See the examples below:
Incorrect use of std::async
#include <iostream>
#include <future>
class AbsClass {
public:
virtual int f() = 0;
};
class ImplClass : public AbsClass {
public:
int f() override { return 21; }
};
int func(AbsClass &asbclass) {
return 210 + asbclass.f();
}
int main() {
ImplClass ic;
AbsClass &ac = ic;
// This causes a compilation failure:
std::future<int> res = std::async(&func, ac);
std::cout << res.get() << std::endl;
}
Failure displayed
/usr/include/c++/7/future:1745:5: error: invalid abstract parameter type ‘AbsClass’
main.cpp:4:7: note: because the following virtual functions are pure within ‘AbsClass’:
class AbsClass {
^~~~~~~~
main.cpp:6:17: note: virtual int AbsClass::f()
virtual int f() = 0;
Correct use of std::async
#include <iostream>
#include <future>
class AbsClass {
public:
virtual int f() = 0;
};
class ImplClass : public AbsClass {
public:
int f() override { return 21; }
};
int func(AbsClass *asbclass) {
return 210 + asbclass->f();
}
int main() {
ImplClass ic;
AbsClass &ac = ic;
std::future<int> res = std::async(&func, &ac);
std::cout << res.get() << std::endl;
}
The arguments needs to be stored, which means they are copied. And references can't be copied.
Therefore a reference wrapper was introduced, that can store references while also being able to be copied. You can use it with the helper function std::ref and std::cref:
std::future<int> res = std::async(&func, std::ref(ac)); // Pass ac by reference
I have the following code:
#include <iostream>
using namespace std;
class A
{
int m_value;
public:
A(int value)
{
m_value = value;
funcA(&A::param);
}
void funcA(void (A::*function)(int))
{
(this->*function)(m_value);
}
void param(int i)
{
cout << "i = " << i << endl;
}
};
int main()
{
A ob(10);
return 0;
}
I have a class in which I call a function that receives another function as parameter. The function call is at line funcA(&A::param). What I want is to be able to pass a function as parameter without being necessary to specify the class scope: funcA(¶m). Also I didn't want to use typedefs that's why I have the code a little 'dirty'.
Is there any possibility to achieve this?
This cannot be done. A function pointer in a class must be identified using the class scope (A::function)
That is kind of ugly.
The first thing you should look at doing is recoding things to use inheritence and dynamic dispatch instead. To do this you change the A class to have a virtual method that funcA calls
class A {
...
void funcA () {
custom_function(m_value);
}
protected:
virtual void custom_function (int)=0;
}
Now for every different custom_function you want to use, you declare a new class derived from A, and implement the function in there. It will automagically get called from funcA:
class A_print : public A {
public:
virtual void custom_function (int param) {
std::cout << "param was " << param << std::endl;
}
}
If that isn't flexible enough for you, the next best C++-ish solution would be to implement a functor (an object that acts as a function, possibly even overriding the ()operator.
I don't understand why you can't just do this:
#include <iostream>
using namespace std;
class A
{
int m_value;
public:
A(int value)
{
param(value);
}
void param(int i)
{
cout << "i = " << i << endl;
}
};
int main()
{
A ob(10);
return 0;
}