Reputation: 73
I am trying to figure out this assignment from my level 2 class. We are to create a class called Number, derived from std::string. the only code in this class is to be two constructors, a default and one that takes a string as an arguement. I have:
class Number : public string {
public:
Number();
Number(string set);
}
The constructors are then coded as:
Number::Number() : string("0") { } // default constructor sets data string to "0"
Number::Number(string set) : string(set) { }
So far so good. Then we are to take two classes that we have been developing, Double and Integer, and derive them from Number. Within these two classes we used to have a double and an int respectively as the data member. Now, because of inheritance, we are supposed to have a built in data section (string). The issue that I am having is that all of my operator=() overloads are now "recursive on all paths" leading to a stackoverflow at runtime. I will show an example of the Double constructor that takes a string, and the equals function that causes the infinite recursion.
Double::Double(string d) : Number(d)
{
// overloaded constructor that takes a string argument
if (isNaN(d)) {
*this = "0.0";
}
else {
*this = d;
}
// used for setting the value of a data member with a string
void Double::operator=(string d)
{
if (isNaN(d)) {
*this = "0.0";
}
else {
*this = d;
}
}
}
I see where the recursion is happening as *this is calling the overloaded = which calls itself since I am using *this in the = function itself. So what would the proper syntax be for setting the data member to a supplied value. Before it was just this->dataMemberName = supplied value of proper type.
It should be noted that my non-string constructors do set the value of an instanced object:
Double::Double(int d) : Number(to_string(d)){}
but the second I try to do anything with them, + - * /, the = function is called and then the error happens again.
Upvotes: 1
Views: 147
Reputation: 761
After discussion in comments I decided to rewrite my answer so that it is more clear what I mean.
You should just call the base class operator=
and let it handle member assignment.
You have class Number
defined like this:
class Number : public string {
public:
Number();
Number(string set);
};
Can this class work for us, as we want it without any modifications? Let's look.
First thing we need is
operator=
in base class.
operator=
is neither declared, nor delete
d in class Number
which means that if you call Number& Number::operator=(Number const&)
this function will be generated for you by compiler. So we are good here.
Second thing which is important for my solution to work is conversion from
std::string
toNumber
.
There is constructor Number::Number(std::string)
in class Number
. Fortunately it's not declared explicit
co it can be used implicitly (with explicit
constructor it would be more verbose, but also possible). Compiler will use this constructor when it needs to convert std::string
into Number
. One-parameter constructors are sometimes called converting constructors.
Ok, so we have second requirement fulfilled.
That's all we need from base class!
Now to work.
We begin with creation of a helper function:
std::string check_for_NaN(std::string s)
{
if(isNaN(s)) { return "0.0"; }
return s;
}
Now we can simplify Double
's constructor:
Double::Double(std::string s): Number(check_for_NaN(s)) //no magic here
{}
And we can create our long awaited operator=
for class Double
:
Double& operator=(std::string rhs)
{
Number::operator=(check_for_NaN(rhs)); //here we have magic, explained below
//if Double has some members of its own, copy them here
return *this;
}
So, what happens when we call 'Number::operator=(check_for_NaN(rhs));'?
check_for_NaN(rhs)
returns us proper string object.Number::operator=(std::string)
but can't find it.Number::operator=(const Number&)
!std::string
to Number
.Number::Number(std::string)
constructor that is not explicit!std::string rhs
it creates a temporary object of class Number
.Upvotes: 1
Reputation: 11002
You can specify directly that you want to use std::string
's operator=
:
#include <string>
using namespace std;
class Number : public string
{
public:
Number();
Number(string set);
};
Number::Number() : string("0") {}//default constructor sets data string to "0"
Number::Number(string set) : string(set) {}
class Double : public Number {
public:
//using Number::operator=;
Double(string d);
void operator=(string d);
double val;
};
bool isNaN(string d) { return false; }
Double::Double(string d) : Number(d) {//overloaded constructor that takes a string argument
if(isNaN(d))
{
string::operator=("0.0");
}
else
{
string::operator=(d);
}
}
void Double::operator=(string d)//used for setting the value of a data member with a string
{
if(isNaN(d))
{
string::operator=("0.0");
}
else
{
string::operator=(d);
}
}
int main()
{
Double d("3");
d = "4";
return 0;
}
Upvotes: 1
Reputation: 118350
Just add:
using std::string::operator=;
Abbreviated example:
#include <string>
class Number : public std::string {
public:
};
class Double : public Number {
public:
using std::string::operator=;
Double()
{
*this="0.0";
}
};
Upvotes: 2