I would like to write a program in C++ which contains an array of function pointers.
Here is the code:
#include <iostream>
using namespace std;
class MyClass {
int a, b;
public:
MyClass(int i, int j) : a(i), b(j) {}
int add() { return a + b; }
int sub() { return a - b; }
};
void func(int (MyClass::* funcPtr[])(), MyClass& a, int i) {
if (i == 0) {
funcPtr[i] = &MyClass::add;
funcPtr;
}
if (i == 1) {
funcPtr[i] = &MyClass::sub;
funcPtr;
}
cout << " Result: " << (a.*funcPtr[i])() << endl;
}
int main(){
int auswahl = 0;
int i = 4, j = 5;
cout << "Which function? [0]-Add [1]-Substract\n";
cin >> select;
MyClass a(i,j);
func(NULL, a, select);
}
After playing around a lot I got the program to compile successfully. But it throws "Write Access Violation" on running.
The problem seems to be related to:
funcPtr[i] = &MyClass::add;
funcPtr[i] = &MyClass::sub;
It'd be very nice, if you could help me solve the problem.
Thank you so much and have a happy time!
As you pass NULL or nullptr in your function, so this line:
funcPtr[i] = &MyClass::add;
Is writing at index i into a null array!
You'd have to provide an array for your function to write into:
MyClass a(i,j);
int (MyClass::* funcPtr[2])();
func(funcPtr, a, select);
Note that using std::array instead of c-style array would avoid this problem, since they are not nullable:
void func(std::array<int (MyClass::*)(), 2> funcPtr, MyClass& a, int i) {
// ...
}
// ...
std::array<int (MyClass::*)(), 2> funcPtr;
func(funcPtr /* cannot pass null */, a, i);
Related
#include <bits/stdc++.h>
using namespace std;
struct stu {
int n;
stu(int _n = 0):n(_n) { }
int add(int a, int b = n-1) {
return a + b;
}
};
int main() {
stu obj = stu(5);
cout << obj.add(10) << endl;
}
The compiler shows the message " invalid use of
non-static data member 'stu::n' ".
What is wrong with this code. Any help would be great.
Thanks.
You can't use default arguments this way. Consider writing two separate functions:
struct stu {
int n;
int add(int a, int b) { return a + b; }
int add(int a) { return a + n - 1; }
}
i have this code which uses a function pointer to point 3 functions sum, subtract, mul. it works well. but now the problem is that i have functions with different no.of parameters and different data types. how to implement this.
int add(int a, int b)
{
cout<<a+b;
}
int subtract(int a, int b)
{
cout<<a-b;
}
int mul(int a, int b)
{
cout<<a*b;
}
int main()
{
int (*fun_ptr_arr[])(int, int) = {add, subtract, mul};
unsigned int ch, a = 15, b = 10,c=9;
ch=2;
if (ch > 4) return 0;
(*fun_ptr_arr[ch])(a, b);
return 0;
}
The simple answer is that technically you can't do this. You could do some manipulations using an array as input for all these functions, but you will still have to know exactly what to pass to each function. From a software engineering perspective, you should not do this - I suggest you take a look at the nice answers here: C++ Function pointers with unknown number of arguments
A slightly different approach using objects to implement the required behavior. In order to have a truly generic kind of solution, we need to use Interfaces.
Dismantle the data and operation i.e keep them separately.
//Interface which describes any kind of data.
struct IData
{
virtual ~IData()
{
}
};
//Interface which desribes any kind of operation
struct IOperation
{
//actual operation which will be performed
virtual IData* Execute(IData *_pData) = 0;
virtual ~IOperation()
{
}
};
Now, every operation knows the kind of data it work on and will expect that kind of data only.
struct Operation_Add : public IOperation
{
//data for operation addition.
struct Data : public IData
{
int a;
int b;
int result;
};
IData* Execute(IData *_pData)
{
//expected data is "Operation_Add::Data_Add"
Operation_Add::Data *pData = dynamic_cast<Operation_Add::Data*>(_pData);
if(pData == NULL)
{
return NULL;
}
pData->result = pData->a + pData->b;
return pData;
}
};
struct Operation_Avg : public IOperation
{
//data for operation average of numbers.
struct Data : public IData
{
int a[5];
int total_numbers;
float result;
};
IData* Execute(IData *_pData)
{
//expected data is "Operation_Avg::Data_Avg"
Operation_Avg::Data *pData = dynamic_cast<Operation_Avg::Data*>(_pData);
if(pData == NULL)
{
return NULL;
}
pData->result = 0.0f;
for(int i = 0; i < pData->total_numbers; ++i)
{
pData->result += pData->a[i];
}
pData->result /= pData->total_numbers;
return pData;
}
};
Here, is the operation processor, the CPU.
struct CPU
{
enum OPERATION
{
ADDITION = 0,
AVERAGE
};
Operation_Add m_stAdditionOperation;
Operation_Avg m_stAverageOperation;
map<CPU::OPERATION, IOperation*> Operation;
CPU()
{
Operation[CPU::ADDITION] = &m_stAdditionOperation;
Operation[CPU::AVERAGE] = &m_stAverageOperation;
}
};
Sample:
CPU g_oCPU;
Operation_Add::Data stAdditionData;
stAdditionData.a = 10;
stAdditionData.b = 20;
Operation_Avg::Data stAverageData;
stAverageData.total_numbers = 5;
for(int i = 0; i < stAverageData.total_numbers; ++i)
{
stAverageData.a[i] = i*10;
}
Operation_Add::Data *pResultAdd = dynamic_cast<Operation_Add::Data*>(g_oCPU.Operation[CPU::ADDITION]->Execute(&stAdditionData));
if(pResultAdd != NULL)
{
printf("add = %d\n", pResultAdd->result);
}
Operation_Avg::Data *pResultAvg = dynamic_cast<Operation_Avg::Data*>(g_oCPU.Operation[CPU::AVERAGE]->Execute(&stAverageData));
if(pResultAvg != NULL)
{
printf("avg = %f\n", pResultAvg->result);
}
If you have the following functions
int f1(int i);
int f2(int i, int j);
You can define a generic function type like this
typedef int (*generic_fp)(void);
And then initialize your function array
generic_fp func_arr[2] = {
(generic_fp) f1,
(generic_fp) f2
};
But you will have to cast the functions back
int result_f1 = ((f1) func_arr[0]) (2);
int result_f2 = ((f2) func_arr[1]) (1, 2);
Obviously, it does not look like a good way to build a program
To make code look a little bit better you can define macros
#define F1(f, p1) ((f1)(f))(p1)
#define F2(f, p1, p2) ((f2)(f))(p1, p2)
int result_f1 = F1(func_arr[0], 2);
int result_f2 = F2(func_arr[1], 1, 2);
EDIT
Forgot to mention, you also have to define a type for every type of function
typedef int (*fi)(int); // type for function of one int param
typedef int (*fii)(int, int); // type for function of two int params
And to then cast stored pointers to those types
int result_f1 = ((fi) func_arr[0]) (2);
int result_f2 = ((fii) func_arr[1]) (1, 2);
Here is a complete example
#include <iostream>
typedef int (*generic_fp)(void);
typedef int (*fi)(int); // type for function of one int param
typedef int (*fii)(int, int); // type for function of two int params
#define F1(f, p1) ((fi)(f))(p1)
#define F2(f, p1, p2) ((fii)(f))(p1, p2)
int f1(int i);
int f2(int i, int j);
int main()
{
generic_fp func_arr[2] = {
(generic_fp) f1,
(generic_fp) f2
};
int result_f1_no_macro = ((fi) func_arr[0]) (2);
int result_f2_no_macro = ((fii) func_arr[1]) (1, 2);
int result_f1_macro = F1(func_arr[0], 2);
int result_f2_macro = F2(func_arr[1], 1, 2);
std::cout << result_f1_no_macro << ", " << result_f2_no_macro << std::endl;
std::cout << result_f1_macro << ", " << result_f2_macro << std::endl;
return 0;
}
int f1(int i)
{
return i * 2;
}
int f2(int i, int j)
{
return i + j;
}
The code above produces the following output
4, 3
4, 3
I am making a class inherited program in c++. Its function is to determane whenever a triangle is right and to calculate its area.
Here is the program:
#include <iostream>
using namespace std;
class Puncte
{
public:
int x1,y1;
int x2,y2;
int x3,y3;
Puncte(int a, int b, int c, int d, int e, int f):x1(a),y1(b),x2(c),y2(d),x3(e),y3(f){}
void AfisareP()
{
cout<<x1<<y1<<x2<<y2<<x3<<y3<<endl;
}
};
class Latura
{
protected:
int l1, l2, l3;
public:
void LatimeaL(int a, int b, int c)
{
l1 = a;
l2 = b;
l3 = c;
}
};
class Triunghi: public Latura
{
public:
int AriaTrDr()
{
return l1*l3/2;
}
};
int main()
{
Puncte p(2,2,2,2,2,2);
Latura l;
l.LatimeaL(1,2,4);
Triunghi t;
if (p.x1 == p.x3 && p.y1 == p.y2)
{
cout << "Triunghi dreptunghic!" << endl;
cout << t.AriaTrDr() << endl;
}
return (0);
}
Everthing is working fine but it doesnt show the correct result but the adress and i dont know how to fix it.
This is the result.
Triunghi dreptunghic!
513242112
You are calling l.LatimeaL(1,2,4); on the object l.
The object t is created with Triunghi t;. It is not initialized by calling the Latimeal function. Therefore you are getting an undefined value.
You need to cal the t.Latimeal(1,2,4) function to initialize it, after creating the object.
Why can't use nullptr in the constructor function?( the function name: Wine) When i try to do this, the program will break down and no any error report maybe because i don't the reason for that.
#ifndef WINE_H_
#define WINE_H_
#include<iostream>
#include<string>
#include<valarray>
using std::string;
using std::valarray;
template<typename T1, typename T2>
class Pair //member of the wine
{
private:
T1 a;
T2 b;
public:
T1 & first(){ return a; }
T2 & second(){ return b; }
T1 first()const{ return a; }
T2 second()const{ return b; }
Pair(const T1 & aval, const T2 & bval) :a(aval), b(bval){}
Pair(){}
};
typedef valarray<int>ArrayInt;
typedef Pair<ArrayInt, ArrayInt>PairArray;
class Wine
{
private:
string name;
PairArray bt;
int years;
public:
Wine();
Wine(const char * a, int y,int b[], int c[]); //no problem
Wine(const char * a, int y); //here is that problem function
void GetBottles(); //no problem
void Show()const; //no problem
int Sum(){ return bt.second().sum(); }
};
Wine::Wine(const char * a, int y) :name(a), years(y), bt(ArrayInt(0, y), ArrayInt(0, y)){}
**//When I am trying to use nullptr to instead 0 in the ArrayInt(0,y),the whole program will break down during work.**
Wine::Wine(const char * a, int y, int b[], int c[]) :bt(ArrayInt(b, y), ArrayInt(c, y))
{
name = a;
years = y;
}
Wine::Wine() :bt(ArrayInt(),ArrayInt())
{
name = "null";
years = 0;
}
void Wine::GetBottles()
{
std::cout << "Please input the years and the bottles\n";
for (int i = 0; i < years; i++)
{
std::cout << "input the year: ";
(std::cin >> bt.first()[i]).get();
std::cout << "input the bottles";
(std::cin >> bt.second()[i]).get();
}
}
void Wine::Show()const
{
using std::cout;
using std::endl;
for (int i = 0; i < years; i++)
{
cout << bt.first()[i] << '\0' << bt.second()[i] << endl;
}
}
#endif
#include<iostream> //test part
#include"wine.h"
int main(void)
{
using std::cin;
using std::cout;
using std::endl;
cout << "Enter name of wine: ";
char lab[50];
cin.getline(lab, 50);
cout << "Enter number of years: ";
int yrs;
cin >> yrs;
Wine holding(lab, yrs);
holding.GetBottles();
holding.Show();
return 0;
}
Thank your for your help!
This is a funny one. The reason why it breaks in one example, but not another is following:
There are two different constructors for std::valarray (more than that, but those two matter):
valarray( const T& val, std::size_t count ); // 1
valarray( const T* vals, std::size_t count ); // 2
When you use 0 (valarray(0, y)) you are calling the first version - creating an array of y elements, where every element is initialized to 0.
But when you are calling it with nullptr, you are calling the second version of it - trying to initialize your new array with a copy from an array pointed to by the first argument to the constructor. But your first argument is nullptr, and any attempt to use at as an array triggers undefined behavior, and program crashes.
Here I have a very simple program. My aim is to let b equal c, that is to copy all the content of c into b. But I don't know how. The getdata() function returns a pointer pointing to array of objects c, but how can it be used to put c into b?
#include<iostream>
#include<stdlib.h>
using namespace std;
class A
{
public:
A(int i,int j):length(i),high(j){}
int length,high;
};
class B
{
private:
A c[3] = {A(9,9),A(9,9),A(9,9)};
public:
A* getdata()
{
return c;
}
};
int main()
{
A b[3]={A(0,0),A(0,0),A(0,0)};
B *x = new B();
cout<< x->getdata() <<endl;
cout << b[1].length<<endl;
return 0;
}
In modern C++, make yourself a favor and use a convenient container class to store your arrays, like STL std::vector (instead of using raw C-like arrays).
Among other features, std::vector defines an overload of operator=(), which makes it possible to copy a source vector to a destination vector using a simple b=c; syntax.
#include <vector> // for STL vector
....
std::vector<A> v; // define a vector of A's
// use vector::push_back() method or .emplace_back()
// or brace init syntax to add content in vector...
std::vector<A> w = v; // duplicate v's content in w
That's a possible partial modification of your code, using std::vector (live here on codepad):
#include <iostream>
#include <vector>
using namespace std;
class A
{
public:
A(int l, int h) : length(l), high(h) {}
int length, high;
};
class B
{
private:
vector<A> c;
public:
const vector<A>& getData() const
{
return c;
}
void setData(const vector<A>& sourceData)
{
c = sourceData;
}
};
int main()
{
vector<A> data;
for (int i = 0; i < 3; ++i) // fill with some test data...
data.push_back(A(i,i));
B b;
b.setData(data);
const vector<A>& x = b.getData();
for (size_t i = 0; i < x.size(); ++i) // feel free to use range-for with C++11 compilers
cout << "A(" << x[i].length << ", " << x[i].high << ")\n";
}
Instead of creating an array of A i.e. 'b' in main, create a pointer to A. And then initialize it by calling the getdata().
A *b;
B *x = new B();
b = x->getdata();
Here is an example
#include <iostream>
#include <algorithm>
class A
{
public:
A( int i, int j ) : length( i ), high( j ){}
int length, high;
};
class B
{
private:
A c[3] = {A(9,9),A(9,9),A(9,9)};
public:
A* getdata()
{
return c;
}
};
int main()
{
A b[3] = { A(0,0), A(0,0), A(0,0) };
B *x = new B();
A *c = x->getdata();
std::copy( c, c + 3, b );
for ( const A &a : b ) std::cout << a.length << '\t' << a.high << std::endl;
delete []x;
return 0;
}
The output is
9 9
9 9
9 9
Instead of standard algorithm std::copy you may use an ordinary loop. For example
for ( size_t i = 0; i < 3; i++ ) b[i] = c[i];