将从std::string派生的类派生的类的数据成员设置为值



我正试图从我的2级课程中找出这个作业。我们将创建一个名为Number的类,它派生自std::string。这个类中唯一的代码是两个构造函数,一个是默认构造函数,另一个是将字符串作为参数的构造函数。我有:

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) { }

到目前为止还不错。然后我们要取两个我们一直在开发的类,Double和Integer,并从Number派生它们。在这两个类中,我们曾经分别有一个double和一个int作为数据成员。现在,由于继承,我们应该有一个内置的数据段(字符串(。我遇到的问题是,我的所有运算符=((重载现在都是"在所有路径上递归的",导致运行时出现堆栈溢出。我将展示一个Double构造函数的例子,它使用字符串,以及导致无限递归的equals函数。

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;
        }
    }
}

我看到递归发生在哪里,因为*this正在调用重载的=,它调用自己,因为我在=函数本身中使用*this。那么,将数据成员设置为提供的值的正确语法是什么呢。以前只是这个->dataMemberName=提供了正确类型的值。

需要注意的是,我的非字符串构造函数确实设置了实例化对象的值:Double::Double(int d) : Number(to_string(d)){}但当我尝试对它们执行任何操作时,+-*/,=函数被调用,然后错误再次发生。

只需添加:

using std::string::operator=;

缩写示例:

#include <string>
class Number : public std::string {
public:
};
class Double : public Number {
public:
    using std::string::operator=;
    Double()
    {
        *this="0.0";
    }
};

在评论中讨论后,我决定重写我的答案,以便更清楚地理解我的意思。

您应该只调用基类operator=并让它处理成员分配。

class Number定义如下:

class Number : public string {
public:
    Number();
    Number(string set);
};

这门课能按照我们的要求在不做任何修改的情况下为我们工作吗?让我们看看。

我们首先需要的是基类中的operator=

operator=既没有声明,Number类中也没有deleted,这意味着如果您调用Number& Number::operator=(Number const&),编译器将为您生成此函数。所以我们在这里很好。

对于我的解决方案来说,第二件重要的事情是从std::stringNumber的转换。

Number中存在构造函数Number::Number(std::string)。幸运的是,它没有声明为explicit-co,它可以隐式使用(使用explicit构造函数会更详细,但也是可能的(。编译器将在需要将std::string转换为Number时使用此构造函数。单参数构造函数有时被称为转换构造函数。好的,所以我们已经满足了第二个要求。

这就是我们所需要的基础课!

现在开始工作。

我们从创建一个辅助函数开始:

std::string check_for_NaN(std::string s)
{
    if(isNaN(s)) { return "0.0"; }
    return s;
}

现在我们可以简化Double的构造函数:

Double::Double(std::string s): Number(check_for_NaN(s)) //no magic here
{}

我们可以为类Double:创建期待已久的operator=

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;
}

那么,当我们调用'Number::operator=(check_for_NaN(rhs((;'时会发生什么呢?

  1. check_for_NaN(rhs)向我们返回正确的字符串对象
  2. 编译器查找Number::operator=(std::string),但找不到它
  3. 发现它可以生成Number::operator=(const Number&)
  4. 编译器检查它,这样的运算符会有所帮助
  5. 如果我们能把CCD_ 23转换成CCD_
  6. 但我们可以!有一个Number::Number(std::string)构造函数不是显式的
  7. 编译器生成赋值运算符
  8. 它从std::string rhs创建一个类为Number的临时对象
  9. 调用生成的运算符
  10. 我们都很高兴,因为它成功了

您可以直接指定要使用std::stringoperator=:

#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;
}

最新更新