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;
}
Related
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 would like to have a unique_ptr class member that points to the base class, but later in the constructor through polymorphism can be changed to point to a sister class that also derives from the same base class.
While I don't get any errors in the constructor setting this polymorphism, it does not seem to work correctly, since I get error messages that my polymorphic pointer can't find a member of the sister class to which I thought the pointer was now pointing.
How do I correctly achieve polymorphism here?
class A {
int bar;
};
class B : public A {
int foo;
};
class C: public A {
C();
std::unique_ptr<A> _ptr; // changing to std::unique_ptr<B> _ptr removes the "class A has no member 'foo'" error
};
C::C() : A()
{
_ptr = std::make_unique<B>(); // no errors here
int w = _ptr->foo; // class A has no member 'foo'
}
When you assign
_ptr = std::make_unique<B>();
This works because B is a derived class of A, however _ptr is still a unique_ptr to the base class. You can't change the type of a variable after it's declared.
So what are your options?
Because you know that _ptr stores a pointer to the derived class B, you can do a cast after dereferencing it:
_ptr = std::make_unique<B>();
// derefence the pointer, and cast the reference to `B&`.
B& reference_to_sister = (B&)(*_ptr);
int w = reference_to_sister.foo;
If you take this approach, you'll have to somehow keep track of which derived class is in _ptr, or you'll run the risk of running into bugs.
Alternatively, if you're using C++17, you can use std::variant:
class C : public A {
void initialize(A& a) {
// Do stuff if it's the base class
}
void initialize(B& b) {
// Do different stuff if it's derived
int w = b.foo;
}
C() {
_ptr = std::make_unique<B>(); // This works
// This takes the pointer, and calls 'initialize'
auto initialize_func = [&](auto& ptr) { initialize(*ptr); };
// This will call 'initialize(A&)' if it contains A,
// and it'll call 'initialize(B&)' if it contains B
std::visit(initialize_func, _ptr);
}
std::variant<std::unique_ptr<A>, std::unique_ptr<B>> _ptr;
};
In fact, if you use std::variant this will work even if A and B are completely unrelated classes.
Here's another short variant example
#include <variant>
#include <string>
#include <iostream>
void print(std::string& s) {
std::cout << "String: " << s << '\n';
}
void print(int i) {
std::cout << "Int: " << i << '\n';
}
void print_either(std::variant<std::string, int>& v) {
// This calls `print(std::string&) if v contained a string
// And it calls `print(int)` if v contained an int
std::visit([](auto& val) { print(val); }, v);
}
int main() {
// v is empty right now
std::variant<std::string, int> v;
// Put a string in v:
v = std::string("Hello, world");
print_either(v); //Prints "String: Hello, world"
// Put an int in v:
v = 13;
print_either(v); //Prints "Int: 13"
}
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.
I have two classes
class A { C* c; }
class B { D* d; }
and find I need to construct a std::vector whose elements are either A or B (with the sequence decided at run time. So I constructed a polymorphic
class Poly {
int oType;
void* oPtr;
}
as well as constructor
Poly::Poly(int type)
{
if (type == 1) oPtr = new (A*) oPtr();
if (type == 2) oPtr = new (B*) oPtr();
oType = type;
}
along with a similarly structured destructor. Now
std::vector<Poly*> test;
works. However, I am having trouble accessing the subobjects.
I tried
if (test->oType == 1) test->oPtr->a;
if (test->oType == 1) test->(A*)oPtr->a;
if (test->oType == 1) (A*)(test->oPtr)->a;
all giving me the compiler error:
'void*' is not a pointer-to-object type
How do I convince the compiler that it's OK to reference a, if I know that the type of oPtr is A*?
How do I convince the compiler that it's OK to reference a, if I know
that the type of oPtr is A*?
Strictly I think the answer to that is: ((A*)(test->oPtr))->a. The better way to do that in C++ uses the cast operator: static_cast<A*>(test->oPtr)->a
HOWEVER This is not typically how this problem is addressed in c++. So I have provided a more usual approach that you may find useful:
class Poly
{
public:
virtual ~Poly() {}
virtual void do_something() = 0; // each sub-type has its own version of this
};
class A: public Poly
{
public:
void do_something() /* override */ // c++11 only
{
std::cout << "Doing something A specific\n";
}
};
class B: public Poly
{
public:
void do_something() /* override */ // c++11 only
{
std::cout << "Doing something B specific\n";
}
};
int main()
{
std::vector<Poly*> polys;
// create data structure
polys.push_back(new A);
polys.push_back(new A);
polys.push_back(new B);
polys.push_back(new A);
// use objects polymorphically
for(size_t i = 0; i < polys.size(); ++i)
polys[i]->do_something();
// clean up memory (consider using 'smart pointers')
for(size_t i = 0; i < polys.size(); ++i)
delete polys[i];
}
As others mentioned, the polymorphic way is to use virtual functions.
Here is an implementation using smart pointers. The creator class is responsible for creating the Poly object we are asking for. This isolates the creation to one class.
Note that there are more sophisticated ways of doing this. The goal here is to show, more or less, how it would be done using C++.
#include <vector>
#include <memory>
#include <iostream>
class Poly
{
public:
virtual void Test() = 0;
};
typedef std::unique_ptr<Poly> PolyPtr;
class A : public Poly
{
public:
void Test() { std::cout << "Test for A" << "\n"; }
};
class B : public Poly
{
public:
void Test() { std::cout << "Test for B" << "\n"; }
};
class PolyCreator
{
public:
PolyPtr CreatePolyObject(int oType)
{
switch( oType )
{
case 1:
return PolyPtr(new A());
case 2:
return PolyPtr(new B());
}
throw "Could not find type in list";
}
};
int main()
{
PolyCreator pCreator;
std::vector<PolyPtr> PolyPtrVect;
// create objects
PolyPtrVect.push_back(pCreator.CreatePolyObject(1));
PolyPtrVect.push_back(pCreator.CreatePolyObject(2));
// call Test functions for each
std::vector<PolyPtr>::iterator it = PolyPtrVect.begin();
while ( it != PolyPtrVect.end())
{
(*it)->Test();
++it;
}
}
Output:
Test for A
Test for B
Note
There is only one if() statement that is isolated to the PolyCreator class.
There are no memory leaks due to usage of std::unique_ptr.
Poly is an abstract class. All derived classes must implement the Test function.
I have a class with an const abstract member. Since it is abstract, the object must reside in a higher scope. However, it may be edited in this higher scope. I have made this MWE, and added comments explaining what I am trying to achieve (.i.e. I know this does NOT achieve what I want).
Besides commenting the hell out of it, what can be done to stop the user from editing the object. Preferably, an idiot proof method (optimally, compile error)
#include <iostream>
class Foo
{
private:
const int * p_abstract_const;
//int my application this is a pointer to abstract object
public:
Foo(const int * p_new_concrete_const)
{
p_abstract_const = p_new_concrete_const;
}
void printX()
{
std::cout << *p_abstract_const << std::endl;
}
};
int main()
{
int concrete_nonconst = 666;
Foo foo(&concrete_nonconst); // I want this NOT to compile
//const int concrete_const(1);
//Foo foo(&concrete_const); // only this should compile
foo.printX();
concrete_nonconst=999; // so that this will NOT be possible
foo.printX();
}
You can make your non-const int* constructor private without providing an implementation:
class Foo
{
private:
const int * p_abstract_const;
//int my application this is a pointer to abstract object
Foo(int * p_new_concrete_const);
public:
Foo(const int * p_new_concrete_const)
{
p_abstract_const = p_new_concrete_const;
}
void printX()
{
std::cout << *p_abstract_const << std::endl;
}
};
int main()
{
int concrete_nonconst = 666;
Foo foo(&concrete_nonconst); // This won't compile
const int concrete_const(1);
Foo foo(&concrete_const); // But this will
foo.printX();
concrete_nonconst=999; // so that this will NOT be possible
foo.printX();
}