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();
}
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 am new to the std::function and trying to implement a callback function. In the following code "Callback_t" contains a function that holds a vector of function to be called. Class "other" is a nested class inside "SomeClass". An object of "SomeClass" contains an array of nested class object "b". The "other" class constructor assigns a function pointer to "fptr". I push this function in to the vector of callback class "Callback_t". When I run this code, I get the segmentation fault when the first function in the vector is invoked. I am not able to figure out what is wrong with the statement
this->loc_ptr->set_of_cb.push_back(this->b[i].fptr);
However if I replace it with
this->loc_ptr->set_of_cb.push_back(std::bind(&other::func, &(this->b[i])))
the code works perfectly. I need help to understand what's wrong with the original statement.
#include <functional>
#include <iostream>
#include <vector>
typedef std::function<void(void)> func_type;
class Callback_t {
public:
std::vector<func_type> set_of_cb;
void myCallback()
{
for (int i = 0; i < set_of_cb.size(); i ++){
set_of_cb[i]();
}
}
};
class SomeClass;
class SomeClass {
private:
Callback_t *loc_ptr;
int a[10];
class other{
public:
int id;
SomeClass *loc;
func_type fptr;
other(){};
other(SomeClass *loc, int id){
this->id = id;
this->loc =loc;
fptr = std::bind(&other::func,this);
}
void func(void){
this->loc->a[id] = loc->a[id] * id;
return;
}
};
public:
other *b;
//other b[10];
SomeClass(Callback_t *a = nullptr){
this->loc_ptr = a;
this->b = new other[10];
for(int i =0; i <10;i++){
this->a[i] = i;
this->b[i] = other(this, i);
this->loc_ptr->set_of_cb.push_back(this->b[i].fptr);
}
}
void read(void){
for(int i =0; i <10;i++){
std::cout<<a[i]<<std::endl;
}
}
};
int main()
{
Callback_t *tmp;
tmp = new Callback_t;
SomeClass tmp1(tmp);
tmp1.read();
tmp->myCallback();
tmp1.read();
delete tmp;
}
other(SomeClass *loc, int id){
this->id = id;
this->loc =loc;
fptr = std::bind(&other::func,this);
}
The constructor binds fptr to this, which is the constructed object. Now, pay careful attention:
this->b[i] = other(this, i);
This performs the following sequence of events. There are quite a few things happening here, that are crucial to this mystery:
A temporary other object gets constructed, and its constructor does what it does. Note that the object is temporary, so its constructor ends up binding its fptr to a temporary object! You're beginning to see the problem, but let's close the loop, anyway:
The object gets assigned to this->b[i]. This is effectively a copy.
The original temporary objects gets destroyed.
The end result is that b[i]'s bound function ends up getting bound to a temporary object that is now destroyed. This results in undefined behavior and your crash.
And with your working alternative:
this->loc_ptr->set_of_cb.push_back(std::bind(&other::func, &(this->b[i])))
You are binding the std::function to a valid instance of the object, in b[i].
That's it.
The other answer explains what is going wrong in your code. What is left to do is to show case a more canonical example of achieving what you go for (with a little help from lambda functions). Of course, std::bind() also works, but it is pre C++11 and I think nowadays most would rather do it as I do in my code below.
#include <iostream>
#include <functional>
#include <vector>
class Foo {
public:
void FooFun() {
std::cout << "Foo::FooFun() called" << std::endl;
}
};
class Bar {
public:
void BarFun() {
std::cout << "Bar::BarFun() called" << std::endl;
}
};
using CallbackFun_t = std::function<void()>;
using Callbacks_t = std::vector<CallbackFun_t>;
int main(int argc, const char * argv[]) {
Foo foo{};
Bar bar{};
Callbacks_t callbacks
{ [&foo]{ foo.FooFun();}
, [&bar]{ bar.BarFun();}
};
for( auto& cb : callbacks ) {
cb();
}
return 0;
}
I have a C-style function, which stores another function as an argument. I also have an object, which stores a method that must be passed to the aforementioned function. I built an example, to simulate the desired situation:
#include <functional>
#include <iostream>
void foo(void(*f)(int)) {
f(2);
}
class TestClass {
public:
std::function<void(int)> f;
void foo(int i) {
std::cout << i << "\n";
}
};
int main() {
TestClass t;
t.f = std::bind(&TestClass::foo, &t, std::placeholders::_1);
foo( t.f.target<void(int)>() );
return 0;
}
What is expected is that it will be shown on screen "2". But I'm having trouble compiling the code, getting the following message on the compiler:
error: const_cast to 'void *(*)(int)', which is not a reference, pointer-to-object, or pointer-to-data-member
return const_cast<_Functor*>(__func);
As I understand the use of "target", it should return a pointer in the format void () (int), related to the desired function through std :: bind. Why didn't the compiler understand it that way, and if it is not possible to use "target" to apply what I want, what would be the alternatives? I don't necessarily need to use std :: function, but I do need the method to be non-static.
This is a dirty little hack but should work
void foo(void(*f)(int)) {
f(2);
}
class TestClass {
public:
void foo(int i) {
std::cout << i << "\n";
}
};
static TestClass* global_variable_hack = nullptr;
void hacky_function(int x) {
global_variable_hack->foo(x);
}
int main() {
TestClass t;
global_variable_hack = &t;
foo(hacky_function);
return 0;
}
//can also be done with a lambda without the global stuff
int main() {
static TestClass t;
auto func = [](int x) {
t->foo(x); //does not need to be captured as it is static
};
foo(func); //non-capturing lambas are implicitly convertible to free functions
}
I have been trying to implement a callback function in c++. Within a class, I have a struct, a number of methods, and a method that creates an instance of the struct with one of the other methods as its argument.
The struct has many other variables, but an illustration is depicted here:
class MYCLASS
{
public:
MYCLASS();
struct TEST{
std::function<int(int)> foo;
};
int plus(int x){
return x + 1;
}
int minus(int x){
return x - 1;
}
void sim(){
TEST T; // make an instance of TEST
T.foo = plus(5); // assign TEST.foo a function (plus or minus)
T.foo(); // call the method we assigned
}
};
Within the sim method, I want to create an instance of test and give it either plus or minus, depending on some criterion. Both lines where I try and give the instance T a plus function and subsequently call it are incorrect.
If you want to delay the call to T.foo, then you could use a lambda like this:
T.foo = [this](int x) { return plus(x); };
T.foo(5);
Option - 1
If the member functions plus() and minus() are simple enough like you have shown, you can make them as lambda functions inside the struct TEST.
Since the capture-less lambdas can be stored in typed function pointers, the following will do what you want.
See live demo
#include <iostream>
class MYCLASS
{
int m_var = 5; // just for demonstration
public:
MYCLASS() = default;
struct TEST
{
using fPtrType = int(*)(int); // function pointer type
const fPtrType foo1 = [](int x) { return x + 1; }; // plus function
const fPtrType foo2 = [](int x) { return x - 1; }; // minus function
};
void sim()
{
TEST T;
std::cout << "Answer from int PLUS(int): " << T.foo1(m_var) << std::endl;
std::cout << "Answer from int MINUS(int): " << T.foo2(m_var) << std::endl;
}
};
Option - 2
If the above alter a lot in your code, use typed function pointer again for member functions and do as follows; which will avoid unnecessary copying(by capturing) the class instance to the lambda and template instantiation and other performance issues comes along with std::function as well.
See live demo
#include <iostream>
class MYCLASS
{
using fPtrType = int(MYCLASS::*)(int); // class member function pointer type
public:
MYCLASS() = default;
struct TEST { fPtrType foo = nullptr; };
int plus(int x) { return x + 1; }
int minus(int x) { return x - 1; }
void sim()
{
TEST T;
T.foo = &MYCLASS::plus; // now you can
std::cout << "Answer from int PLUS(int): " << (this->*T.MYCLASS::TEST::foo)(5) << std::endl;
//^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ syntax would be a bit ugly
// later same ptr variable for minus()
T.foo = &MYCLASS::minus;
int answer = (this->*T.MYCLASS::TEST::foo)(5);
std::cout << "Answer from int MINUS(int): " << answer << std::endl;
}
};
int main()
{
MYCLASS obj;
obj.sim();
return 0;
}
Output:
Answer from int PLUS(int): 6
Answer from int MINUS(int): 4
I know this has been asked so many times, and because of that it's difficult to dig through the cruft and find a simple example of what works.
I've got this, it's simple and it works for MyClass...
#include <iostream>
using std::cout;
using std::endl;
class MyClass
{
public:
MyClass();
static void Callback(MyClass* instance, int x);
private:
int private_x;
};
class EventHandler
{
public:
void addHandler(MyClass* owner)
{
cout << "Handler added..." << endl;
//Let's pretend an event just occured
owner->Callback(owner,1);
}
};
EventHandler* handler;
MyClass::MyClass()
{
private_x = 5;
handler->addHandler(this);
}
void MyClass::Callback(MyClass* instance, int x)
{
cout << x + instance->private_x << endl;
}
int main(int argc, char** argv)
{
handler = new EventHandler();
MyClass* myClass = new MyClass();
}
class YourClass
{
public:
YourClass();
static void Callback(YourClass* instance, int x);
};
How can that be rewritten so EventHandler::addHandler() will work with both MyClass and YourClass. I'm sorry but it's just the way my brain works, I need to see a simple example of what works before I can comprehend why/how it works. If you've got a favorite way to make this work now's the time to show it off, please markup that code and post it back.
[edit]
It was answered but the answer was deleted before I could give the checkmark.
The answer in my case was a templated function. Changed addHandler to this...
class EventHandler
{
public:
template<typename T>
void addHandler(T* owner)
{
cout << "Handler added..." << endl;
//Let's pretend an event just occured
owner->Callback(owner,1);
}
};
Instead of having static methods and passing around a pointer to the class instance, you could use functionality in the new C++11 standard: std::function and std::bind:
#include <functional>
class EventHandler
{
public:
void addHandler(std::function<void(int)> callback)
{
cout << "Handler added..." << endl;
// Let's pretend an event just occured
callback(1);
}
};
The addHandler method now accepts a std::function argument, and this "function object" have no return value and takes an integer as argument.
To bind it to a specific function, you use std::bind:
class MyClass
{
public:
MyClass();
// Note: No longer marked `static`, and only takes the actual argument
void Callback(int x);
private:
int private_x;
};
MyClass::MyClass()
{
using namespace std::placeholders; // for `_1`
private_x = 5;
handler->addHandler(std::bind(&MyClass::Callback, this, _1));
}
void MyClass::Callback(int x)
{
// No longer needs an explicit `instance` argument,
// as `this` is set up properly
cout << x + private_x << endl;
}
You need to use std::bind when adding the handler, as you explicitly needs to specify the otherwise implicit this pointer as an argument. If you have a free-standing function, you don't have to use std::bind:
void freeStandingCallback(int x)
{
// ...
}
int main()
{
// ...
handler->addHandler(freeStandingCallback);
}
Having the event handler use std::function objects, also makes it possible to use the new C++11 lambda functions:
handler->addHandler([](int x) { std::cout << "x is " << x << '\n'; });
Here's a concise version that works with class method callbacks and with regular function callbacks. In this example, to show how parameters are handled, the callback function takes two parameters: bool and int.
class Caller {
template<class T> void addCallback(T* const object, void(T::* const mf)(bool,int))
{
using namespace std::placeholders;
callbacks_.emplace_back(std::bind(mf, object, _1, _2));
}
void addCallback(void(* const fun)(bool,int))
{
callbacks_.emplace_back(fun);
}
void callCallbacks(bool firstval, int secondval)
{
for (const auto& cb : callbacks_)
cb(firstval, secondval);
}
private:
std::vector<std::function<void(bool,int)>> callbacks_;
}
class Callee {
void MyFunction(bool,int);
}
//then, somewhere in Callee, to add the callback, given a pointer to Caller `ptr`
ptr->addCallback(this, &Callee::MyFunction);
//or to add a call back to a regular function
ptr->addCallback(&MyRegularFunction);
This restricts the C++11-specific code to the addCallback method and private data in class Caller. To me, at least, this minimizes the chance of making mistakes when implementing it.
Note that with C++20's bind_front you can simplify add_callback for class member functions to:
template<class T> void addCallback(T* const object, void(T::* const mf)(bool,int))
{
callbacks_.emplace_back(std::bind_front(mf, object));
}
What you want to do is to make an interface which handles this code and all your classes implement the interface.
class IEventListener{
public:
void OnEvent(int x) = 0; // renamed Callback to OnEvent removed the instance, you can add it back if you want.
};
class MyClass :public IEventListener
{
...
void OnEvent(int x); //typically such a function is NOT static. This wont work if it is static.
};
class YourClass :public IEventListener
{
Note that for this to work the "Callback" function is non static which i believe is an improvement. If you want it to be static, you need to do it as JaredC suggests with templates.
A complete working example from the code above.... for C++11:
#include <stdlib.h>
#include <stdio.h>
#include <functional>
#if __cplusplus <= 199711L
#error This file needs at least a C++11 compliant compiler, try using:
#error $ g++ -std=c++11 ..
#endif
using namespace std;
class EventHandler {
public:
void addHandler(std::function<void(int)> callback) {
printf("\nHandler added...");
// Let's pretend an event just occured
callback(1);
}
};
class MyClass
{
public:
MyClass(int);
// Note: No longer marked `static`, and only takes the actual argument
void Callback(int x);
private:
EventHandler *pHandler;
int private_x;
};
MyClass::MyClass(int value) {
using namespace std::placeholders; // for `_1`
pHandler = new EventHandler();
private_x = value;
pHandler->addHandler(std::bind(&MyClass::Callback, this, _1));
}
void MyClass::Callback(int x) {
// No longer needs an explicit `instance` argument,
// as `this` is set up properly
printf("\nResult:%d\n\n", (x+private_x));
}
// Main method
int main(int argc, char const *argv[]) {
printf("\nCompiler:%ld\n", __cplusplus);
new MyClass(5);
return 0;
}
// where $1 is your .cpp file name... this is the command used:
// g++ -std=c++11 -Wall -o $1 $1.cpp
// chmod 700 $1
// ./$1
Output should be:
Compiler:201103
Handler added...
Result:6
MyClass and YourClass could both be derived from SomeonesClass which has an abstract (virtual) Callback method. Your addHandler would accept objects of type SomeonesClass and MyClass and YourClass can override Callback to provide their specific implementation of callback behavior.
If you have callbacks with different parameters you can use templates as follows:
// compile with: g++ -std=c++11 myTemplatedCPPcallbacks.cpp -o myTemplatedCPPcallbacksApp
#include <functional> // c++11
#include <iostream> // due to: cout
using std::cout;
using std::endl;
class MyClass
{
public:
MyClass();
static void Callback(MyClass* instance, int x);
private:
int private_x;
};
class OtherClass
{
public:
OtherClass();
static void Callback(OtherClass* instance, std::string str);
private:
std::string private_str;
};
class EventHandler
{
public:
template<typename T, class T2>
void addHandler(T* owner, T2 arg2)
{
cout << "\nHandler added..." << endl;
//Let's pretend an event just occured
owner->Callback(owner, arg2);
}
};
MyClass::MyClass()
{
EventHandler* handler;
private_x = 4;
handler->addHandler(this, private_x);
}
OtherClass::OtherClass()
{
EventHandler* handler;
private_str = "moh ";
handler->addHandler(this, private_str );
}
void MyClass::Callback(MyClass* instance, int x)
{
cout << " MyClass::Callback(MyClass* instance, int x) ==> "
<< 6 + x + instance->private_x << endl;
}
void OtherClass::Callback(OtherClass* instance, std::string private_str)
{
cout << " OtherClass::Callback(OtherClass* instance, std::string private_str) ==> "
<< " Hello " << instance->private_str << endl;
}
int main(int argc, char** argv)
{
EventHandler* handler;
handler = new EventHandler();
MyClass* myClass = new MyClass();
OtherClass* myOtherClass = new OtherClass();
}