How to overload operator= used in initializing a new object? - c++

I'm new to C++ and I'm trying to understand how Class works. I made a simple example for myself when I encounter this problem. My class has one private property num and I'm trying to initialize it with an int this way: Number one = Number::ONE; but it doesn't work. However, when I do this it works fine: Number one; one = Number::ONE. I prefer the first option. Please help!
Here is my complete code:
class Number {
public:
enum {ONE, TWO, THREE, FOUR};
Number();
void print() const;
Number& operator=(int);
private:
int num;
};
Number& Number::operator=(int n) {
num = n;
return *this;
}
int main(int argc, const char * argv[]) {
Number n = Number::ONE; // doesn't work :(
n.print();
return 0;
}
Number::Number() {
num = 0;
}
void Number::print() const {
cout << num << endl;
}

In C++, when you write
Number one = Number::ONE;
the compiler will not use the assignment operator to initialize one. The operator= function is only invoked when you have an existing object that you want to reassign a new value. Instead, in this case, the compiler tries to invoke a conversion constructor, a constructor that takes in an object of the type on the right-hand side of the equality. Since you haven't defined a constructor like that, you're getting a compiler error.
One way to do this would be something like this:
class Number {
public:
Number(int value); // <-- Conversion constructor
...
};
Number::Number(int value) {
num = value;
}
Now, the code you've given here will compile properly.
You may want to do some reading into copy constructors, assignment operators, conversion constructors, and conversion assignment operators, since they're one of the trickier parts of routine C++ and often trip up people transitioning from basic C++ to more intermediate-level language techniques.

you didn't overload the constructor to take an integer as parameter that is why you get the error:
class Number
{
public:
enum {ONE, TWO, THREE, FOUR};
Number(int x) : num(x){}
void print() const;
Number& operator=(int);
private:
int num;
};

Related

Use class with operator []

i am trying to implement a "Integer" class with expect that it will work like a build-in type int. But i am having a problem: i can't use this class in operator [] like int See my code below:
#include <iostream>
using namespace std;
class Integer
{
private:
int Value;
public:
Integer(int x = 0)
{
Value = x;
}
void SetValue(int x)
{
Value = x;
}
int GetValue()
{
return Value;
}
Integer& operator [] (Integer X);
};
Integer& Integer::operator [] (Integer X)
{
// Code
}
int main()
{
Integer X[10];
Integer I(5);
int i = 5;
for(int i=0; i<10; ++i)
X[i].SetValue(i+1);
cout << X[i].GetValue() << endl; // It still work
cout << X[I].GetValue() << endl; // Doesn't work
return 0;
}
What is a way (exclude cast operator) to make operator [] understand my Integer type like it does with int?
You are thinking about this the wrong way around. You don't need to overload the [] operator on your own class, you actually need your class to be convertable to int, which can be done by overloading the cast operator.
class Integer
{
public:
operator int () const { return Value; }
};
There's a bit of confusion here. The declaration of an array of type T takes the form
T t[n];
where n is a compile time evaluable constant expression for the array size.
This does not invoke any [] operator defined within T, and neither does a subsequent access of an element via the expression t[i] for an integral type i.
If, in your case, you want X[I] to be compilable then you need to provide an operator that allows I to be treated as an array index (more formally the language requires a primitive integral type). A cast operator to int is the obvious choice, with
operator int() const
{
return Value;
}
being the implementation.
You'll need to add a type cast operator to your class. This allows your class to be converted to a compatible type. See here for more information: http://www.cplusplus.com/doc/tutorial/typecasting/
This function should do the trick for your class.
operator int() const { return GetValue(); }
Actually, you don't need to overload the [] operator.
You just need to make sure that you can convert your Integer into an int with int int operator.
Something like this would work better.
operator int() const
{ return GetValue(); }
Then you should also be carefull with your prints.
X[i].GetValue() is wrong since i = 10 in your exemple. This will result in an execution error.
X[I].GetValue() is wrong in your exemple because de conversion between your class and an int is not possible without I.getValue(). I am surprise this doesn't result in a compilation error but overloading the int operator will result this issue tho.

Default return of class instance without member function

Is it possible to make a class return a particular member variable by default when the object is used somewhere(without using a getter member function)?
If I have this class:
class A{
public:
A(int nr) : number(nr){};
~A();
int getNr(){ return this->number };
int number;
};
To set and get its number later in the program, I can do this:
int main(){
A thing(23);
std::cout<<"Your number is: "<<thing.getNr();
return 0;
}
But what I would like to do is this:
std::cout<<"Your number is: "<<thing;
And get the exact same result, make it return the member variable "number" by default. Can this be done/set somehow?
I know somebody might be thinking "Why not just use integers as they are for that?" - I'm making a class which should be able to "turn into" any type and then act like the assigned type, it would be nice if I could make it act like ints, doubles, strings in that regard too later.
Your specific example invokes the << stream insertion operator on an A. This operator can be overloaded to do what you want:
#include <iostream>
class A{
public:
A(int nr) : number(nr) { }
~A() { }
int getNr() const { return this->number; }
int number;
};
std::ostream& operator<<(std::ostream& os, const A& a) {
os << a.getNr();
return os;
}
int main(int, char *[]) {
A a(42);
std::cout << a << std::endl; // prints 42
}
Note here I have made some other minor fixes to your code (fixed a missing ; and removed some unnecessary ones; added const to getNr()).
For other situations, such as passing arguments of type A to functions that accept parameters of a different type, you can define user-defined conversion operators that are called by the compiler to convert an A to a different type. For example:
void doSomething(int x) {
// ...
}
class A{
public:
A(int nr) : number(nr){}
~A(){}
int getNr(){ return this->number; }
int number;
operator int() { return getNr(); }
};
int main(int, char *[]) {
A a(42);
doSomething(a); // calls operator int() above
return 0;
}
Be careful with user-defined conversion operators. In particular, it's often best to mark them explicit and use static_cast<T>() to trigger the conversion. Implicit conversions can quickly get you into trouble with overload resolution.

Overloading Multiple Functions with Same Parameters

I'm given to understand, thanks to the VC++ compiler, that you cannot overload functions with only a differing return type.
class MyClass {
public:
MyClass MyClass::operator+(MyClass other) {
return MyClass(n + other.getn());
}
MyClass() = default;
MyClass(int my_n) : n{ my_n } {}
int getn() {
return n;
}
private:
int n{ 0 };
};
int main(){
MyClass m1(7), m2(5);
MyClass m3 = m1 + m2;
return 0;
}
However, what if I would like to return an integer, say 12, when I add them, I cannot simply add them together and overload the operator+ again because it doesn't allow overloading where the only difference is the return type. I'm very new to C++. The only solution I could come up with is:
int i = (m1+m2).getn();
But that seems wasteful to create an instance when you will never use it again.
I think what you want is to be able to write int i = m1 + m2;, which means you should create a conversion operator.
class MyClass
{
operator int()
{
return n;
}
};
int i = m1 + m2; //creates temporary, calls operator int, saves value in i
It will still create a temporary, but that's how operator+ works. You could always write int i = m1.getn() + m2.getn();, too.
Overloading doesn't consider about return type.
From the standard, $13.3/1 Overload resolution [over.match]
The selection criteria for the best function are the number of arguments, how well the arguments
match the parameter-type-list of the candidate function, how well (for non-static member functions) the object matches the implicit object parameter, and certain other properties of the candidate function.
and
128) ... candidate call functions that cannot be differentiated one from the other by overload
resolution because they have identical declarations or differ only in their return type.
You might want to provide two operator+ for MyClass, they only differ at the return type of MyClass and int, and use them as
MyClass m1(7), m2(5);
MyClass m3 = m1 + m2;
int x = m1 + m2;
but the return value could be omitted, then which one should be invoked? It's ill-formed.
m1 + m2;
// or m1.operator+(m2);
You could provide another named member function for it, such as
class MyClass { public:
int add_return_int(MyClass other) {
return n + other.getn();
}
...
or as free function
int add_return_int(MyClass lhs, MyClass rhs) {
return lhs.getn() + rhs.getn();
}

How do I create a class that can initialize C++ data types?

The title basically says it all. I mainly want to do this so that I can create an object (say, a custom string object) that can initialize the parameters of other functions in other APIs. Here's an example of me trying to get a custom integer class to work:
#include <iostream>
using namespace std;
class test
{
public:
int member;
test(int i) : member(i) {}
friend int &operator=(int &i, test t);
};
int &operator=(int &i, test t)
{
return (i = t.member);
}
int main()
{
int i;
test t = 90;
cout << (i = t);
return 0;
}
Unfortunately I receive an error saying that operator= needs to be a member function. I understand the C++ standard's goal in preventing static and non-member overloads for the assignment operator from being implemented, but is there any other way to do this? Thanks for any help/suggestions!
This is not done with an assignment operator but with an overloaded typecast. This would make your main function work like expected:
#include <iostream>
using namespace std;
class test
{
public:
int member;
test(int i) : member(i) {}
operator int() const {return member;}
};
int main()
{
int i;
test t = 90;
cout << (i = t);
return 0;
}
What you are trying to do needs an conversion operator
operator int()
{
return this->member;
}
For the class you are trying to write(containing only integer members), You do not need to overload the = operator.
= operator is one of the member functions that is generated by the compiler by default for every class. Caveat is, it does a simple bit by bit copy(shallow copy) of class members, since you have only integers it should be good enough for you.
You would need to overload the = operator if you had dynamically allocated pointers as member functions, because in that case a shallow copy of those pointers would result in all the objects containing a member pointer pointing to the same dynamic memory location & if one of the object finishes it lifetime, other objects are left with a dangling pointer.
As #Tony, aptly points in out comments Shallow copy is usually bad but not always. See his comments for a scenario.
If at all you want to overload the assignment operator check out the Copy and Swap Idiom to do it right way.
You should also check out the Rule of Three.
Try this:
class test
{
public:
int member;
test(int i) : member(i) {}
operator int() {return this->member;}
};
int main(void)
{
int i;
test t = 90;
cout << (i = t);
return 0;
}
The assignment operator cannot be a friend function. The assignment operator can only be declared as a non-static member function. This is to ensure that it receives the L-value as its first operand. The same is true for the [], (), and -> operators. In your case, since int is an build-in type, you cannot use member function. You can implement operator int() to cast your user-defined type to int.

Is it possible to assign object to int?

I have a CCounter class which holds and integer value protected by mutex. I've defined several operators like post/pre inc/dec returning an integer so I can do:
CCounter c(10);
int i = c++;
but what do I do with a simple assignment like i = c ? I tried to define friend operator= but it gives me
operator=(int&, const CCounter&)’ must be a nonstatic member function
error. Please, advise. Thanks.
You need to define a casting operator that casts from CCounter to int. Add this member to your class:
operator int() const {
return ...;
}
As you have found out, the assignment operator must be a member function of a class. As ints are not classes, you can't write operator=() for them. The alternative, as others have pointed out is to write a function that converts to an int. I would strongly suggest you write a named function like ToInt() to do this, rather than using a conversion operator, which can be the source of non-obvious bugs.
G'day,
Shouldn't you be defining an accessor function instead if you're just "getting" the current value of the counter?
Something like:
int GetCounter();
Anything else is sort of disguising the intention of what you're trying to do. IMHO Natch! (-:
HTH
cheers,
You need to define operator int() to allow the conversion of your class to an int. For example:
class CCounter
{
public:
CCounter(int val) : m_val(val)
{
}
operator int() const
{
return m_val;
}
private:
int m_val;
};
int main(int argc,char *argv[])
{
CCounter c(10);
int n = c;
std::cout<<n<<"\n";
return 0;
}
As said use the int() operator. Here a code snippet :
#include <iostream>
class CCounter
{
public:
CCounter(int i = 0) : _count(i) {}
operator int() { return _count; }
private:
int _count;
};
int main()
{
CCounter counter(4);
int c = counter;
std::cout << "Counter = " << c << std::endl;
return 0;
}
You said:
"I've defined several operators like post/pre inc/dec returning an integer".
Now that other answers provided you with a generic way to convert the object to an integer, I would recommend that you change these other operators so that they behave as typically expected.
For instance, pre increment typically returns a reference to the object itself, and post increment typically returns a temporary copy of the original object (prior to the incrementation).
CCounter& operator++() {
++m_val;
return *this;
}
CCounter operator++(int) {
CCounter tmp(*this);
++m_val;
return tmp;
}
Although you have been given a valid solution, I would also consider simply creating a normal function which returns int, such as int GetValue() const, to improve readability and ease of maintenance. Of course this is highly subjective.
#include<iostream>
using namespace std;
class CA {
public:
int a;
CA(int x):a(x)
{
}
operator int() const {
return a;
}
void operator ()() {
}
};
void main(){
CA obj = 100;
int k = obj;
obj();
}