2016-10-27 1 views
1

Я пытаюсь выяснить это назначение из своего класса уровня 2. Мы должны создать класс под названием Number, полученный из std :: string. единственным кодом этого класса является два конструктора, по умолчанию и один, который принимает строку в качестве аргумента. у меня есть:Установка члена данных для класса, производного от класса, полученного из 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. Внутри этих двух классов мы использовали двойной и int соответственно как элемент данных. Теперь из-за наследования мы должны иметь встроенный раздел данных (строка). Проблема, с которой я столкнулась, заключается в том, что все мои перегрузки operator =() теперь «рекурсивные на всех путях», что приводит к переходу stackoverflow во время выполнения. Я покажу пример конструктора 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; 
     } 
    } 
} 

Я вижу, где рекурсии происходит, как * это звонит перегруженные =, который называет себя, так как я использую * это в самой функции =. Итак, каков будет правильный синтаксис для установки элемента данных в заданное значение. До этого было только это-> dataMemberName = заданное значение соответствующего типа.

Следует отметить, что мои нестроковые конструкторы действительно установить значение в инстанс объекта: Double::Double(int d) : Number(to_string(d)){} , но второй я пытаюсь сделать что-нибудь с ними, + - * /, функция = называется, а затем ошибка повторится.

+0

Следует отметить, что мои нестрочные конструкторы устанавливают значение объекта instanced : Двойной :: Двойной (int d): Number (to_string (d)) {}, но второй я пытаюсь что-то с ними сделать, + - * /, вызывается функция =, а затем ошибка повторяется снова. – DRoc101

+0

Если вы хотите добавить информацию к вашему вопросу, измените вопрос. Не используйте комментарии для добавления информации. – Lehu

+3

Неплохая практика заключается в том, что они производятся из 'std :: string' или других стандартных контейнеров, они не предназначены для этого. Обычно у вас просто есть переменная-член 'std :: string'. –

ответ

1

После обсуждения в комментариях я решил переписать свой ответ, чтобы было более ясно, что я имею в виду.

Вы должны просто вызвать базовый класс operator= и позволить ему обрабатывать назначение члена.

Вы class Number определены следующим образом:

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

Может ли этот класс работа для нас, так как мы хотим, без каких-либо изменений? Давайте посмотрим.

Первое, что нам нужно, это operator= в базовом классе.

operator= не является ни объявлен, ни delete d в классе Number, что означает, что если вы звоните Number& Number::operator=(Number const&) эта функция будет генерироваться для вас компилятором. Итак, мы здесь хорошие.

Вторая вещь, которая имеет важное значение для моего решения работы является преобразование std::string в Number.

Существует конструктор Number::Number(std::string) в классе Number. К счастью, он не объявлен explicit co его можно использовать неявно (с конструктором explicit было бы более подробным, но также возможным). Компилятор будет использовать этот конструктор, когда ему нужно будет преобразовать std::string в Number.Однопараметрические конструкторы иногда называются конструкторами преобразования . Итак, мы выполнили второе требование.

Это все, что нам нужно от базового класса!

Теперь работать.

Мы начнем с создания вспомогательной функции:

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

Теперь мы можем упростить конструктор Double «S:

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

И мы можем создать наш долгожданный operator= для класса 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; 
} 

Итак, что происходит, когда мы call 'Number :: operator = (check_for_NaN (rhs));'?

  1. check_for_NaN(rhs) возвращает нам надлежащий строковый объект.
  2. Компилятор ищет Number::operator=(std::string), но не может его найти.
  3. Он находит, что он может генератор Number::operator=(const Number&)!
  4. Компилятор проверяет, поможет ли такой оператор.
  5. Если бы мы могли конвертировать std::string в Number.
  6. Но мы можем! Существует конструктор Number::Number(std::string), который не является явным!
  7. Компилятор генерирует оператор присваивания.
  8. От std::string rhs создает временный объект класса Number.
  9. Вызывается сгенерированный оператор.
  10. Мы все счастливы, потому что это сработало!
+0

Нам не разрешено иметь какой-либо другой код в классе Number, отличный от двух конструкторов. Элемент данных, который мы должны использовать, содержится в std :: string. – DRoc101

+0

'operator =' - такая отличная (или очень сложная, зависящая) функция, которую он часто создает для нас компилятор. Просто используйте '' '' '' '' '' '' '' '' '' '' '' ''. – Lehu

2

Просто добавьте:

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

Вы можете указать непосредственно, что вы хотите использовать 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; 
} 
+0

Честно говоря, я бы предпочел использовать 'operator =' из прямой базы, а не базы базы. Роль базы - вызывать 'operator =' из базы базы. – Lehu

+0

@Lehu Почему? Разве это не просто функция пересылки в этом случае? Может быть, если вы будете следовать идиоме pimpl? В любом случае ОП заявил, что у него могут быть только конструкторы в 'Class Number'. – wally

+0

Если 'class Number' выглядит точно так же, как в вопросе, у него будет' Number :: operator = ', сгенерированный для него компилятором. – Lehu

Смежные вопросы