Проблема с простой перегрузкой функций - PullRequest
0 голосов
/ 20 февраля 2011

Идея набора функций:

Первый аргумент является ссылкой, выделяет пространство для хранения копии тестирования, устанавливает член stany beany для указания на новый блок, копирует тестирование в новый блок и устанавливает член ct beany.

Проблема:

1) Строка, содержащая:

for (int i = 0; i < temp.length(); i++)

Ошибка: выражение должно иметь класс тип

2) Строка, содержащая:

temp[i] = cstr[i];

Ошибка: выражение должно иметь тип указателя на объект

3) перегрузка функции show () для строкового типа не может найти подходящую сигнатуру функции из-за присутствия const

Совсем новый для этих понятий, кто-то может объяснить причину ошибок?

#include "stdafx.h"
#include <iostream>
using namespace std;
#include <cstring>
#include <cctype>
struct stringy {
    char * str; //points to a string
    int ct; //length of string(not counting '\0')
};

void set(stringy & obj,  char cstr);
void show(const stringy & obj, int times=1);
void show(const char * cstr, int times = 1);

int _tmain(int argc, _TCHAR* argv[])
{
    string beany;
    char testing[] = "Reality isn't what it used to be.";

    set(beany, testing);
    show(beany);
    show(beany, 2);
    testing[0] = 'D';
    testing[1] = 'u';
    show(testing);
    show(testing, 3);
    show("Done");
    return 0;
}

void set(stringy & obj, char cstr)
{
    char * temp = new char[cstr];
    obj.str = temp;
    for (int i = 0; i < temp.length(); i++)
    temp[i] = cstr[i];
}

void show(const stringy & obj, int times)
{
    for (int i = 0; i < times; i++)
        cout << obj.str;
}

void show(const char * cstr, int times)
{
    for (int i = 0; i < times; i++)
        cout << cstr;
}

Ответы [ 2 ]

3 голосов
/ 20 февраля 2011

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

Пожалуйста, сделайте себе одолжение и начните с чтения книги на C ++. Список хороших можно найти здесь , а также вы можете найти бесплатные ресурсы в Интернете.

C ++ - это не тот язык, который вы (или любой другой) можете надеяться выучить, просто набрав на нем несколько символов и посмотрев, что происходит ... это просто суицидальный подход к C ++.

EDIT:

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

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

EDIT2:

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

1. Изучай стандарт C ++

#include "stdafx.h"

Если вы изучаете C ++, вам следует отложить в сторону все, что Microsoft говорит вам о языке. Стандарт C ++ никогда не был важен для Microsoft; вероятно, потому что переносимый код представляет собой скорее угрозу для Microsoft, чем полезен для них.

Как только вы знаете C ++ (но только тогда), можно писать код для Microsoft, если это ваша платформа. Но важно, чтобы вы знали, что такое ms-only и что такое C ++. В некоторых случаях разница просто глупа и не заслуживает рассмотрения (например, for определение или обработка ошибок выделения), но иногда вы ДОЛЖНЫ использовать их вариант языка для работы с окнами.

Средства разработки MS великолепны (или, по крайней мере, они были ... Я просто влюблен в VC6, например), но они всегда будут пытаться обмануть вас при написании непереносимого кода. Это делается как в IDE, так и в примерах Windows API. Не попадайтесь в эти ловушки: пишите переносимый код, если у вас нет реальной потребности в коде для конкретной платформы, и всегда помните об этом.

2. Не загрязняйте глобальное пространство имен

using namespace std;

Это плохая идея. Даже если это немного раздражает, гораздо лучше, если вы привыкнете писать std:: перед стандартными функциями. Причины кроются в сложных правилах поиска имен и разрешения перегрузки, которые присутствуют в языке, а также из-за всех имен, которые вы вводите в свое пространство имен, не осознавая их.

Экономия времени при наборе на самом деле не так важна в C ++ (это важно в PERL, если вы пишете одноразовый скрипт ... но не для обычных программ). Гораздо важнее помочь тому, кто читает ваш код (включая вас) и использует std::.

3. Используйте правильное основное объявление

Это опять о том, чтобы не попасть в тупые ловушки MS. Правильное объявление для main -

int main(int argc, const char *argv[])

Вы никогда не должны использовать что-либо еще при изучении C ++. Если инструмент MS, который вы используете, не позволяет вам написать правильное объявление (это не было бы сюрпризом), просто бросьте его прямо сейчас и изучите C ++, используя инструмент, который демонстрирует некоторое уважение к стандарту. Как только вы знаете C ++, вы можете начать использовать непереносимые вещи, если вам действительно нужно, но зная, что это непереносимые вещи.

Mingw - хороший бесплатный компилятор C ++ для Windows, и есть бесплатных хороших IDE , если они вам нравятся. С годами мне нравилось пользоваться хорошим редактором, таким как emacs ( vim тоже хорошо, я использовал его много лет) и компилятором командной строки, но в основном потому, что я работаю на разных языках в нескольких операционных системах, и ни одна IDE не может охватить все это. Я хочу поместить знания низкого уровня (как скопировать фрагмент текста, как искать строку, как попросить завершение, как открыть другой файл) на уровне пальца и не нужно сознательно думать, в какой IDE я нахожусь просто чтобы найти правильную команду. Вы не можете играть Шопена , если вам каждый раз приходится думать, где находится G # на клавиатуре.

Может быть, я просто старый, однако ...; -)

4. Выберите разумное соглашение об именах

struct stringy {
    char * str; //points to a string
    int ct; //length of string(not counting '\0')
};

В вашем коде вы называете класс stringy. Будет лучше, если вы привыкнете к тому, что является наиболее распространенным соглашением об именах в C ++ для классов, то есть вместо этого оно называется Stringy.

Стандартная библиотека C ++ не следует этому соглашению, но эти классы всегда будут иметь префикс std::.

Мой совет также НЕ использовать идею системной венгерской нотации вызова переменных в зависимости от типа C ++ (например, iIndex, sFileName), который иногда присутствует в документации MS. Эта идея не масштабируется и просто означает, что вы будете использовать плохие имена для всех ваших переменных.

5. Проблемы с заданной функцией

void set(stringy & obj, char cstr)
{
    char * temp = new char[cstr];
    obj.str = temp;
    for (int i = 0; i < temp.length(); i++)
    temp[i] = cstr[i];
}

В этой функции есть несколько ошибок:

  • Вы хотите передать char *, а не char. char содержит место для одного символа, и вместо этого вы хотите инициализировать ваш экземпляр stringy последовательностью символов. В C ++ вы можете использовать для этого указатель на символ, потому что в памяти имеется специальная поддержка последовательностей символов, которые закрываются специальным ascii char NUL (обратите внимание на одиночный "L" , символ ASCII NUL в C ++ пишется '\0' и его не следует путать с указателем NULL). Предпочтительным способом обработки последовательностей символов в C ++ является стандартный класс std::string, но последовательности символов, определенные в NUL , также полностью поддерживаются для обратной совместимости с C.

  • Указатель, однако, является просто адресом символа ... за этим символом будут следовать другие символы, пока вы не найдете закрывающий '\0', но указатель не имеет члена length (на самом деле членов нет все, это примитивный тип, такой как int или double).

    Чтобы узнать длину последовательности символов, которая была передана с помощью указателя, существует стандартная функция strlen (которая возвращает количество символов в последовательности , исключая завершающую '\0') , Таким образом, ваш код должен выглядеть примерно так:

    void set(stringy & obj, char *cstr)
    {
        char * temp = new char[1 + strlen(cstr)];
        obj.str = temp;
        strcpy(obj.str, cstr);
    }

Я также использовал стандартную функцию strcpy, которая копирует последовательность символов, включая маркер конца '\0'. Возможная реализация strcpy (здесь, чтобы показать идею '\0' -определенных строк) следующая:

    char *mystrcpy(char *dest, const char *src)
    {
        int i = 0;
        while (src[i] != '\0')
        {
            dest[i] = src[i];
            i++;
        }
        dest[i] = '\0';
        return dest;
    }

6. Распределение памяти

Класс stringy плохо спроектирован (в C ++ нет большой разницы между struct и class: только то, что используется по умолчанию для видимости). Конкретное конструирование и уничтожение не обрабатываются там, где они должны быть (внутри строкового класса), а для класса, спроектированного таким образом, конструирование присвоения и копирования также должно обрабатываться или запрещаться.

Как следствие, ваша программа просто забывает утечку памяти из-за освобождения памяти (обычно это не серьезная проблема для main, но важно понимать проблему).

Надеюсь, эта проблема только потому, что книга еще не пришла, чтобы объяснить эти концепции.

В любом случае я нахожу странной книгу, которая говорит о new[], но не о delete[] (может быть, есть причина, по которой ваша книга не указана как хорошая книга).

Правильно реализованный stringy, если IMO будет выглядеть примерно так:

struct stringy
{
    int size;    // Number of characters EXCLUDING ending '\0'
    char *ptr;   // Pointer to first character

    stringy(const char *s = "")
        : size(strlen(s)), ptr(new char[1 + size])
    {
        strcpy(ptr, s);
    }

    ~stringy()
    {
        delete[] ptr;
    }

    stringy(const stringy& other)
        : size(other.size), ptr(new char[1 + size])
    {
        strcpy(ptr, other.ptr);
    }

    stringy& operator=(const stringy& other)
    {
        char *newptr = new char[1 + other.size];
        strcpy(newptr, other.ptr);
        delete[] ptr;
        ptr = newptr;
        size = other.size;
        return *this;
    }
};
0 голосов
/ 20 февраля 2011

temp является постоянным символом *.Этот тип не предоставляет никаких средств длины - он не объект и не имеет метода-члена length ().Используйте std::string - вот для чего.

...