for homework, I need to write a program in cpp with a class composed of an array of pointer to function and operators. I need to create an operator + so as when in the main, this would happen:
int main()
{
int SIZE = 5;
ptrF* arrPtrF = new ptrF[SIZE];
arrPtrF[0] = add;
arrPtrF[1] = sub;
arrPtrF[2] = mult;
arrPtrF[3] = div1;
arrPtrF[4] = pow;
Delegate D1(arrPtrF, SIZE)
cout<< D1[0](6, 7) + D1[0](1, 2)<<endl;
}
the outcome is 15
I am finding difficulty with writing the operator+ ( which in this case need to take take a object parameter)
at first i tried this:
Delegate Delegate:: operator + (const Delegate& b)
{
Delegate tmp;
tmp.m_ptrF[i] = m_ptrF[i] + b.m_ptrF[i];
return tmp;
}
but it gave me an error about the i and b.m_ptrF->initialized i and something about an enum type.
then i tried this:
int Delegate:: operator + (const Delegate& b)
{
int tmp;
int i, x,y;
tmp = m_ptrF[i](x, y) + b.m_ptrF[i](x, y);
return tmp;
}
but it gives me an error->initialized x,y,i knowing that i is index and x,y the parameters of the pointer to function.
what can i do to make it work?
It looks like D1[0](6, 7) is supposed to perform 6 + 7 returning an int and D1[0](1, 2) is supposed to perform 1 + 2 also returning an int. So the addition in D1[0](6, 7) + D1[0](1, 2) is just a regular int addition.
So in other words you are not supposed to be overloading Delegate::operator+ instead you are supposed to writing something like this
XXX Delegate::operator[](int i) const
{
...
}
where XXX is a function like type that will perform the addition on the later parameters.
So XXX will be something like
class XXX
{
public:
int operator()(int x, int y) const
{
...
}
...
};
But XXX will have to perform addition, or substraction or whatever, as appropriate.
So the expression D1[0](6, 7) becomes temp(6,7) where temp is an object of the XXX type above.
At least that's my best interpretation. It's clear that you have misunderstood your requirements.
Related
Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed last month.
Improve this question
On today's adventofcode, we had a pathfinding problem, with persistent states over multiple rounds.
I created a function called solve(startPoint, endPoint) which would calculate the steps to go from one waypoint to the other.
The code that worked fine:
int first = solve(start, end);
int second = solve(end, start);
int third = solve(start, end);
return first + second + third;
The code that did not work:
return solve(start, end) + solve(end, start) + solve(start, end);
And neither did
return (((solve(start, end)) + solve(end, start)) + solve(start, end));
How can I return the accumulated value in one line, without running in some sort of order issue?
The order of parts of a composed expression is not specified in C++ (see https://en.cppreference.com/w/cpp/language/eval_order). Therefore, it is not possible to gather these function calls in a single expression and guarantee a particular order of evaluation.
> How can I return the accumulated value in one line, without running in some sort of order issue?
Try this:
int a, b, c;
return (a = solve(start, end), b = solve(start, end), c = solve(start, end), a + b + c);
It guarantees the evaluation in order from left to right.
From eval_order:
Every value computation and side effect of the first (left) argument of the built-in comma operator , is sequenced before every value computation and side effect of the second (right) argument.
With persistent states, that code looks like this:
int a = c++ + c++ + c++;
there is no strict ordering about these operations. Partial results may even be cached in different CPU registers and get false result, even if the first c++ increments first, the second and third could be already cached on different CPU-registers for speed optimization, because there are likely multiple adder pipelines in a cpu core that can do it in (instruction-level) parallelism.
Try implementing a chain-calculation API like this:
return solve(s,e).addSolve(e,s).addSolve(s,e).result;
Here, the evaluation has to start from first and end at the last because this is just multiple lines of codes in disguise. Something like this:
class FOO
{
public:
BAR result;
FOO(){ result=0;}
FOO(BAR se){ result=se; }
// assuming solution is s+e
FOO solve(BAR s, BAR e)
{
return FOO(s+e);
}
FOO addSolve(BAR s, Bar e)
{
return FOO(result+s+e);
}
};
Ofcourse the upper example does not save the states in the original object. You need something like this really:
class FOO
{
public:
std::shared_ptr<BAR> result;
// creates original store
FOO()
{
result = std::make_shared<BAR>();
*result=0;
}
// re-uses original
FOO(BAR se, std::shared_ptr<BAR> original)
{
result = original;
*result=se;
}
// assuming solution is s+e
FOO solve(BAR s, BAR e)
{
return FOO(s+e,result);
}
FOO addSolve(BAR s, Bar e)
{
return FOO(*result + s + e,result);
}
};
So that you can still use the original object (the one that was created first) for the result.
Even if original object goes out of scope, the second and the third instances still have the exact same result.
If the initial conditions (parameterless default constructor) meet the requirements of addSolve, then you could simply call same addSolve method 3 times after renaming it to just solve:
// dereferencing explicitly
return *foo.solve(s,e).solve(e,s).solve(s,e).result;
// or implicitly from a method
return foo.solve(s,e).solve(e,s).solve(s,e).getResult();
If you make solve an object that holds the parameters and allows for lazy evaluation, you can overload the + operator for this type to guarantee the order of evaluation:
/**
* object simply stores the parameters for evaluation in operator+
*/
struct solve
{
int m_a;
int m_b;
constexpr solve(int a, int b) noexcept
: m_a(a), m_b(b)
{
}
int operator()() const
{
std::cout << "evaluating solve(" << m_a << ", " << m_b << ")\n";
return m_a + m_b;
}
};
int operator+(solve const& s1, solve const& s2)
{
// do operation of the first operand before the second
auto v1 = s1();
return v1 + s2();
}
int operator+(int s1, solve const& s2)
{
// first operand is already evaluated
return s1 + s2();
}
int main()
{
auto result = solve(1, 2) + solve(3, 4) + solve(5, 6);
std::cout << result << '\n';
return 0;
}
Output:
evaluating solve(1, 2)
evaluating solve(3, 4)
evaluating solve(5, 6)
21
In real code I recommend adding the constexpr modifier to solve::operator()() and the + operators, if possible btw...
Note that this may not be the best idea, since seeing the expression solve(1, 2) + solve(3, 4) + solve(5, 6) it's not obvious, that an order of evaluation is enforced here...
I have a class Point which has a member method to get position:
class Point {
private:
int x; int y;
public:
Point(int a, int b) {
x = a; y = b;
}
int getX() { return x; }
int getY() { return y; }
};
These are stored in a list<Point> named listPoints. I have a function which checks whether a position matches any of the points in the list:
bool checkMatch(int x, int y) {
for (Point p : listPoints) {
if (p.getX() == x && p.getY() == y) {
return true;
}
}
return false;
}
Note the . is used to access member methods of Point, but there's another way:
bool checkMatch(int x, int y) {
list<Point>::iterator p = listPoints.begin();
for (; p != listPoints.end(); ++p) {
if (p->getX() == x && p->getY() == y) {
return true;
}
}
return false;
}
What is this function doing differently to the one before, specifically why does . no longer work and I need to use -> instead to access member methods of Point? Are these foreach loops fundamentally different?
They're not different no, with some very minor exceptions. In the second loop, you're using an iterator, which is more-or-less a pointer to the object itself. It can be dereferenced to get the actual object.
You'd use iterators if you wanted to remove some elements. So say instead of checking for matches, you were removing anything that matched, you'd want to iterate with iterators.
Since you are just iterating over the entire range, it's far clearer to use your for-ranged loop. It's easier to write and clearer.
specifically why does . no longer work and I need to use -> instead to access member methods of Point?
Because the iterator is an object, which basically points to the actual object. You cannot override the dot operator, so instead operator-> is overridden to retrieve the object. One could also dereference the iterator like *p, which allows you to use the dot operator (*p).getX()
Are these foreach loops fundamentally different?
They are not fundmentally different. They are subtly different.
It's analogous to:
int a;
int* ptr = &a;
a = 10;
*ptr = 10;
The last two lines are not fundmentally different. An iterator is kinda like a pointer. Its operator* is overloaded such that using *p acts as though you are dereferencing a pointer -- you get a reference to an item in the container.
The second block of code can be changed a bit to resemble the first one.
list<Point>::iterator iter = listPoints.begin();
for (; iter != listPoints.end(); ++iter) {
Point& p = *iter;
if (p.getX() == x && p.getY() == y) {
return true;
}
}
Under the covers, the first block is exactly that.
See the documentation on the range-for loop in the standard for the details.
So looking in IDA i found a function like this
struct exampleStruct {
int a, b, c;
};
void example(exampleStruct *(*exampleList)[3])
{
//blah blah
}
so this is the part that confuses me *(*exampleList)[3])
from just looking at it i would image i would call the function like this
exampleStruct forCall[3];
example(&forCall);
then after it is called i would imagine i can fetch the values like so
//forCall[0].a
//forCall[2].c
//etc...
So my question is, is what i said above correct? e.g. is that how i would call a function like that?
If you want to pass an array of exampleStruct to example, then the latter would like this:
void examplefoo(examplestruct somename[]) {
allnames[0].a += 1;
}
or:
void examplefoo(examplestruct* somename) {
allnames[0].a += 1;
}
Basically both are the same: you give the function a pointer to the first element of you array.
This function will take the first element of the array and increase its .a by 1. Let's see how we can call this function.
First you have to create and array of examplestruct, eg.:
examplestruct somename;
somename.a = 1;
somename.b = 2;
somename.c = 3;
examplestruct othername;
othername.a = 7;
othername.b = 8;
othername.b = 9;
examplestruct allnames[2] = {somename, othername};
And call the function like this:
examplefoo(allnames);
If you then print allnames[0].a you will see that its value is now 2.
I have done numerous searches and found a ton of examples and tutorials but still cannot figure out how to get the value when writing to the [] operator...
I feel like i'm going insane. I must be missing something very simple
as far as i can tell there is a single function for get and set and it looks something like this:
V& operator[](string K);
or this:
double &operator[](int n);
now great, we can get what is:
a[HERE]
as HERE becomes double &operator[](int HERE);
and we can easily work with it
but how do we get what is:
a[4] = HERE
C# has two very clear get and set methods with the value keyword which represents the object being assigned.
public string this[int key]
{
get
{
if(key == 1)
return "1!";
if(key == 2)
return "2!";
else
return "3!";
}
set
{
if( value == "setting") //value is a[3] = THIS
this.isSet = true;
}
}
Don't think of operator[] as a function to get or set, that might be confusing. Think of it as a normal function. In fact, let's re-write it as a normal function:
struct X
{
int arr[10];
int& getIndex(int idx) { return arr[idx]; }
};
//...
//initialize x of type X
x.getIndex(3) = 42;
The method x.getIndex(3) will return a reference to the 4-th element in the member array idx. Because you return by reference, the return value is an l-value and refers to that exact element, so you can assign a value to it, say, 42. This will modify the member x.arr[3] as the function returns an alias for that particular object.
Now you can re-write this in terms of operator[] exactly as before
struct X
{
int arr[10];
int& operator[](int idx) { return arr[idx]; }
};
and get the same result by calling
x[3];
or even
x.operator[](3);
The operator option is just syntactic sugar.
I implemented a class named bignumber that takes a big number as a string and stores it in an array.
I made a friend operation + for it to add two bignumbers. After running I get an error that the program doesn't respond. What is the problem?
.h file:
class bignumber
{
private:
int *number;
int size;
string num;
public:
bignumber(int);
bignumber(string ,int);
~bignumber();
friend bignumber operator+(bignumber,bignumber);
};
definitions:
bignumber :: bignumber(int numsize)
{
this->size= numsize;
this->number= new int[size];
};
bignumber :: bignumber(string inputnum,int numsize)
{
int *number = new int[numsize];
size = numsize;
num = inputnum;
for(int i=0;i<numsize;i++){
number[i] = int(num[i])-48;
};
};
bignumber :: ~bignumber()
{
delete [] number;
};
bignumber operator+(bignumber num1,bignumber num2)
{
if(num2.size>num1.size){
int e = num2.size - num1.size - 1;
int *tempnum = new int [num2.size];
for(int i=0;i<num1.size;i++){
tempnum[e+i] = num1.number[i];
}
delete [] num1.number;
num1.number = new int[num2.size];
for(int i=0;i<num2.size;i++){
num1.number[i] = tempnum[i];
}
delete [] tempnum;
}
else if(num1.size>num2.size){
int e = num1.size - num2.size - 1;
int *tempnum = new int [num1.size];
for(int i=0;i<num2.size;i++){
tempnum[e+i] = num2.number[i];
}
delete [] num2.number;
num2.number = new int[num1.size];
for(int i=0;i<num1.size;i++){
num2.number[i] = tempnum[i];
}
delete [] tempnum;
}
bignumber temp(max(num1.size,num2.size));
int carry = 0;
for(int i = 0;i < temp.size;i++){
temp.number[i] = num1.number[i] + num2.number[i] + carry;
if (temp.number[i] > 10){
temp.number[i] -= 10;
int carry = 1;
}
};
if(carry = 1){
int *temp2 = new int[temp.size+1];
temp2[0] = carry;
for(int j = 1;j < temp.size+1;j++){
temp2[j] = temp.number[j-1];
};
temp.size += 1;
delete [] temp.number;
temp.number = new int[temp.size];
for(int i=0;i<temp.size;i++){
temp.number[i] = temp2[i];
}
delete [] temp2;
};
};
Also I don't know how to define operator >> to input the number. I wrote this as a friend but it doesn't work:
istream& operator>>(string s,int size)
{
bignumber(s,size);
};
1) You haven't provided the copy constructor, so compiler makes the copy constructor with shallow copy. The same goes for operator=. That's very wrong when you manually allocate memory.
Call to operator+ where you pass parameters by value will result in creating two shallow temporary copies of operands. Then you modify these temporaries deleting the pointers and setting them to new values. But operands know nothing about it, their number pointers will still point to deleted memory, so the operands will become unusable and crash your program on any access to them or on destruction (when their destructors will try to delete the already deleted).
You do not return anything in your operator+, but you have to, and there the lack of copy constructor will result in another allocation error.
2) To pass complex objects by value is rarely a good practice, do it only if you have real reasons. Otherwise, use const myclass& param instead. For your operator+, the signature would be bignumber operator+(const bignumber& num1, const bignumber& num2). Yes, since you cannot modify num1 and num2, you will still need a local copy of the number that needs to grow, but this is one copying instead of two that you've got.
3) implementing operator+ is best done when you've already implemented more simple MyClass& MyClass::operator+=(const MyClass& that); After that, you can use
MyClass operator+(const MyClass& first, const MyClass& second)
{
MyClass retval(first);
retval+=second;
return retval;
}
Your operator+ will still be more complex than needed because you haven't provided some essential functions. You resize your number several times -- why don't you make it a member function resize(int newsize)? You could test and debug it separately, then your operators will be much simpler.
...which all leads to an obvious question: why don't you use vector<int> number? It will solve all the problems above: the compiler-generated constructors and operator= will work fine, no allocation nightmares, resize() and lots of other useful functions are already provided and thoroughly tested. Or, you can use string only: ints are actually wasted in your code, since you store only numbers 0..9 in each of them. Define member functions like int2character and character2int, and you've got rid of most of your problems.
4) operator>> for streams should have a signature
istream& operator>>(istream& is, bignumber& num);
and be something like that:
istream& operator>>(istream& is, bignumber& num)
{
string strTmp;
is>>strTmp;
//checks for istream state etc
//...
//calculate size of number from the extracted string
//...
//then construct a temporary
bignumber tmp(strTmp, calcsize);
num=tmp;//don't forget assignment operator
//or
//just provide a method to reset value of bignumber from string
//it can be a member function
num.assign(strTmp);
//or operator=(const string& str);
num=strTmp;
return is;
}
That is, usually to make your stream operator, you use already defined stream operators for other types.
5) you do not reset carry flag in cycle after you've used it.