2013-03-12 2 views
2

Создание пользовательского класса String, и у меня возникли проблемы с перегрузкой оператора ' <' для вывода. Я пробовал несколько разных способов его написания (прокомментировал код ниже, для справки и, поскольку они не работают), и получить различные ошибки. Для начала, Я получаю ошибку, используя код:Проблемы с перегрузкой Оператор «<<»

Ошибка 1: Ошибка C2804: бинарный «оператор < <» имеет слишком много параметров линии 53

Ошибка 2: ошибка C2333: «Строка оператор :: < < ': ошибка в объявлении функции; пропуская функцию: линия тела 53

Ошибка 3: ошибка C2679: двоичный '< <': оператор не найден, который принимает правый операнд типа «String» (или нет приемлемого преобразования), строка 180 (есть пучок из них)

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

Кроме того, я знаю, что «использование пространства имен std» в заголовке - это плохая практика. Извините, это старый файл, с которым я работаю, и я обещаю, что не буду включать его в будущие заголовочные файлы.

Тем не менее, вот код (и спасибо за помощь):

Как я уже сказал, спасибо за тонну до тех, кто читает и реагирует ниже. Я потратил около двух часов, пытаясь найти жизнеспособное решение, и сообщения, которые я искал, были слишком сложны для меня, чтобы понять или не применялись в моем случае. От взгляда на веб-сайт cplusplus я увидел, что функция оператора < < принимает только один параметр, однако у него возникли проблемы, связанные с этим. Если вы, ребята, опубликуете то, что, по вашему мнению, будет работать, я попробую и ответю.

Спасибо всем! Дайте мне знать, не хватает ли какой-либо важной информации.

#pragma once 

#include <iostream> 
#include <sstream> 
using namespace std; 

#define NOT_FOUND -1 

//ostream& operator << (ostream& out, const String& myString); 

// C++ String class that encapsulates an ASCII C-string 
class String 
{ 
public: 
    // Default constructor 
    String() 
    { 
        Text = NULL; 
    } 
     
    // MUST HAVE: Copy-constructor that performs deep copy 
    String(const String& source) 
    { 
        Text = NULL; 
        // Call the assignment operator to perform deep copy 
        *this = source; 
    } 
     
    // Init-constructor to initialize this String with a C-string 
    String(const char* text) 
    { 
        Text = NULL; 
        // Call the assignment operator to perform deep copy 
        *this = text; 
    } 
     
    // Init constructor, allocates this String to hold the size characters 
    String(int size) 
    { 
        Text = new char[size]; 
    } 
     
    // Destructor 
    ~String() 
    { 
        delete[] Text; 
    } 
     
    // This is what I would love to have work. 
    ostream& operator << (ostream& out, const String& myString) 
    { 
        return out << myString.GetText(); 
    } 
    // Returns a new string that corresponds to a substring of this String 
// beginning at startPosition and length chars long; 
// if length = 0 (not specified) then the substring spans from 
// startPosition until the end of this String 
// throws an exception when startPosition is out of bounds 
String Substring(int startPosition, int length) const 
{ 
    char * str = this->GetText(); 
    String returnString; 
    int strLength = length; 
    int x = 0; 

    if(length == 0) 
     strLength = GetLength(str)-startPosition; 

    char* substring = new char[strLength]; 

    // Makes sure the starting position is within the bounds of the String 'this' 
    try 
    { 
     CheckBounds(startPosition, str); 
    } 
    catch(char * error) 
    { 
     cout << error << endl << endl; 
    } 

    // In case the substring length is too long, it cuts short once it reaches the end of the original string. Yu-San, this is #2 on the three options you said I could implement, FYI. 
    while(x < strLength && str[x+startPosition]!='\0') 
    { 
     substring[x] = str[x + startPosition]; 
     x++; 
    } 
    substring[x]='\0'; 
    //for(int x = 0; x<strLength; x++) 
    //{ 
    //returnString = str + startPosition; 
    returnString = substring; 
    //} 

    return returnString;  
} 
    // Assignment operator to perform deep copy 
    String& operator = (const char* text) 
    { 
        // Ddispose of old Text 
        delete[] Text; 
         
        // +1 accounts for NULL-terminator 
        int trueLength = GetLength(text) + 1; 
         
        // Dynamically allocate characters on heap 
        Text = new char[trueLength]; 
         
        // Copy all characters from source to Text; +1 accounts for NULL-terminator 
        for (int i = 0; i < trueLength; i++) 
            Text[i] = text[i]; 
         
        return *this; 
    } 
     
    // Returns the count of characters in a C-string text; NULL-terminator is not counted 
    // static means that the member function neither reads nor 
    // writes any of the class' data members 
    // String::GetLength("blah"); 
    static int GetLength(const char* text) 
    { 
        int x = 0; 
        while(text[x] != '\0') 
            x++; 
         
        return x; 
    } 
     
    // Returns a reference to a single character from this String 
    char& operator [] (int index) const 
    { 
        int length = GetLength(); 
         
        // Check for valid index 
        if ((index < 0) || (index > length)) 
        { 
            stringstream error; 
            error << "operator[] - index " << index << " is out of bounds (0.." << (length - 1) << ")"; 
            throw String(error.str().c_str()); 
        } 
         
        return Text[index]; 
    } 
// Returns the count of characters in the String; NULL-terminator is not counted 
int GetLength() const 
{ 
    return GetLength(Text); 
} 



char* GetText() const 
{ 
    return Text; 
} 

// Finds first index of a symbol not found in "text" in string *this 
int FindFirstNotOf(char * text) 
{ 
    String objectString(*this); 
    int x = 0; // loop counter 
    int firstIndex = 0; // index to return 

    while(text[x]!='\0') 
    { 
     // runs each character in 'text' against each character in the object. 
     for(int y = 0; y<objectString.GetLength(); y++) 
     { 
      if(objectString[x] == text[x]) 
       objectString[x] = '\0'; 
     } 

     x++; 
    } 

    while(objectString[firstIndex]=='\0' && (firstIndex<objectString.GetLength())) 
    { 
     firstIndex++; //keeps running until it Finds a character that wasn't changed to \0 
    } 

    if(firstIndex == objectString.GetLength()) 
     firstIndex = -1; // means it wasn't found. 

    return firstIndex; 
} 

int FindFirstOf(char iWantThis) 
{ 
    String objectString(*this); 
    int firstIndex = 0; // index to return 

    while(objectString[firstIndex]!=iWantThis && (firstIndex<objectString.GetLength())) 
    { 
     firstIndex++; //keeps running until it Finds a character that wasn't changed to \0 
    } 

    if(firstIndex == objectString.GetLength()) 
     firstIndex = -1; // means it wasn't found. 

    return firstIndex; 
} 

int FindLastOf(char iWantThis) 
{ 
    String objectString(*this); 
    int index = 0; 
    int lastIndex = -1; 

    while(objectString[index]!='\0') 
    { 
     if(objectString[index] == iWantThis) 
      lastIndex = index; 
    } 

    return lastIndex; 
} 

// finds a desired char in String object, with default start index of 0 
int Find (char iWantThis, int startIndex = 0) 
{ 
    int index = -1; 
    int ctr = startIndex; 

    String objectString(*this); 

    while(objectString[ctr]!='\0' && index == -1) // runs until it reaches end, or the return index is changed 
    { 
     if(objectString[ctr] == iWantThis) 
      index = ctr; 
     else 
      ctr++; 
    } 

    return index; 
} 

private: 

// Throws an String-type exception when index is out of bounds 
void CheckBounds(int index, const char* source) const 
{ 
    int size = GetLength(source); 

    if(index < 0 && index >=size) 
     throw "Selected Starting Index is Out of Bounds."; 
} 

// The encapsulated C-string 
char* Text; 
}; 


// Stream output operator to print String to output stream 
/* ostream& operator << (ostream& out, const String& myString) 
 * { 
 * return out << myString.GetText(); 
 * }; 
 */ 
+4

Двоичный 'operator <<' должен быть свободной функцией вместо функции-члена. Член 'operator <<' может принимать только один аргумент, который был бы правой частью выражения. У вас, кажется, есть оператор как бесплатная функция в качестве комментария в конце вашего кода. Почему эта попытка потерпела неудачу? – Pablo

+0

@Pablo Спасибо за быстрый ответ. Существует несколько инструкций try/catch с оператором «<<» для проверки границ различных функций, а также другого кода проверки ошибок в классе. Он показывает ту же ошибку, что и «Ошибка 3». В верхней части страницы. Кроме того, спасибо за помощь в формате вопроса :) Когда перегрузка оператора является свободной функцией внизу, класс не знает, что означает «<<». Если я объявляю его вверху, я получаю сообщение об ошибке: «Ошибка C4430: спецификатор отсутствующего типа - предполагается int. Примечание: C++ не поддерживает значение по умолчанию -int« – Reciever80

ответ

2

Вам нужен оператор вставки, чтобы быть свободной функцией:

Внутри вашего класса тело:

class String 
{ 
    friend std::stream& operator <<(std::ostream&, const String&); 
    ... 
}; 

Вне вашего тела класса:

inline std::ostream& operator << (std::ostream& os, const String& myString) 
{ 
    os << myString.GetText(); 
    return os; 
} 

Предполагается, что GetText() является жизнеспособной функцией-членом, которая в вашем текущем фрагменте кода нигде не найдена. Я предполагаю, что у вас есть где-то. Если это public, тогда вам не нужно объявлять дружеские отношения в классе, и вы можете просто использовать оператор вставки свободной функции.

Наконец, предполагается, что оператор реализован в файле заголовка (таким образом, встроенный). Если вы переместите реализацию в файл .cpp, обязательно объявите ее как глобальный прототип в своем заголовке и удалите преамбулу inline в реализации .cpp.

Сторона Примечание: Перерыв привычка класть using namespace std; в заголовочные файлы прямо сейчас. это плохая практика и может иметь нежелательные побочные эффекты для исходных файлов, включая ваш заголовок, который не ожидается, что воздействие пространства имен.

+0

Когда перегрузка оператора является свободной функцией внизу, класс doesn «Не знаю, что означает« << ». Если я объявляю его вверху, я получаю сообщение об ошибке: «Ошибка C4430: Отсутствует спецификатор типа - int. Примечание: C++ не поддерживает значение по умолчанию -int». Оглядываясь назад, вы получите только после того, как разместите свой вопрос онлайн, я понимаю, что строки c работают так же хорошо, но для будущих ссылок, каково было бы решение? – Reciever80

+0

@ Reciever80 Почему «класс» сам использует этот оператор в первую очередь ?? Не должно быть оператора вставки даже * объявленного * в классе, кроме 'friend' decl, и это только при необходимости. Что именно вы пытаетесь использовать оператор вставки свободной функции для * в классе * ?? Можете ли вы опубликовать код, который использует его * в классе *? Помните, что у нас нет вашего кода (отсутствие GetText(), и все переменные-члены являются наилучшим доказательством этого), поэтому мы лечим со слепыми здесь. – WhozCraig

+0

Существует несколько инструкций try/catch с оператором «<<» для проверки границ различных функций, а также другого кода проверки ошибок в классе. Он будет печатать строку, говорящую «вне границ». Я понял, что после публикации этого (эта ироничная задним числом я получаю только после публикации вопросов в Интернете), я мог бы просто использовать c-строки вместо этого. Я добавлю еще несколько функций в OP, просто пытаясь избежать слишком большой информации для людей, читающих. Хотя это действительно отлично работает даже при использовании «Строков» внутри самого класса. Ты мужчина! – Reciever80

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