C ++ классы, объектно-ориентированное программирование - PullRequest
0 голосов
/ 21 января 2010

У меня есть очень простой класс с именем person, который приведен ниже, у меня проблема только с двумя функциями: функцией setstring () и функцией setname (), я вызываю функцию setstring () из функции setname. Единственная проблема, когда в основной функции я пишу
Object.setname ( «Зия»);
Результат в порядке, как показано на экране вывода, Теперь, когда я пишу
Object.setname («Зия ур Рахман»);
Ничего не отображается, так как вы видите экран вывода.

Я знаю, что проблема в том, что я передаю указатель имени в функцию setstring (), но я не совсем понимаю, пожалуйста, объясните подробно, что здесь происходит.

#include<iostream.h>
class person
{
char* name;
public:
person();
void setname(const char*);
void setstring(const char*, char*);
void print()const;
};
person::person()
{
name=new char[3];
strcpy(name,"NILL");
name[3]='\0';
}
void person::setstring(const char* s, char*p)
{
if(s!=NULL)
{
delete[] p;
p=new char[strlen(s)];
strcpy(p,s);
p[strlen(s)]='\0';
}
}
void person::setname(const char* n)
{
setstring(n, name);//passing data member name
}
void person::print()const
{
cout<<"Name: "<<name<<endl;
}
main()
{
person object;
object.setname("Zia ur Rahman");
object.print();
system("pause");
}

альтернативный текст http://img264.imageshack.us/img264/8867/inheritanceimage004.jpg

альтернативный текст http://img263.imageshack.us/img263/3770/inheritanceimage003.jpg

Ответы [ 6 ]

3 голосов
/ 21 января 2010

Конкретная причина, по которой ничего не печатается, заключается в том, что в setstring, p является копией указателя имени, а не ссылкой на него. Попробуйте изменить подпись setstring на:

void setstring(const char* s, char*& p);

(обратите внимание на &).

См. Другие ответы о других существенных ошибках в коде - если эти проблемы не будут устранены, вы, вероятно, получите сбои или странное поведение.

И если целью кода не является просто изучение динамических массивов, используйте вместо него std::string: -).

3 голосов
/ 21 января 2010

Если вы хотите сделать правильное ОО-ориентированное программирование на C ++, вам, возможно, следует избегать прямого управления указателями, но использовать класс строк STL и использовать ссылки вместо указателей. Тогда вам будет легче, и ваш источник должен дать правильный вывод.

В противном случае проверьте ваш конструктор класса person, массив имен содержит только 3 элемента, но вы ссылаетесь на 4-й (индексы 0-2!). Также в методе setstring () вы не выделяете достаточно места для конечного '\ 0' в массиве!

2 голосов
/ 21 января 2010

Для начала:

name=new char[3];
strcpy(name,"NILL");
name[3]='\0';

имя имеет три элемента - вы рассматриваете его так, как если бы оно имело пять элементов. В том же духе:

p=new char[strlen(s)];

должно быть:

p=new char[strlen(s) + 1];

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

2 голосов
/ 21 января 2010

Задумывались ли вы об использовании std :: string из STL?

Хотя первая проблема, которую я вижу, это.

человек :: человек ()
{
имя = новый символ [3];
зЬгср (имя, "NILL");
Имя [3] = '\ 0';
}

Вы выделяете массив символов, размер массива составляет 3 символа, затем копируете в него «NILL» с помощью strcpy, так что вы заполняете массив всеми символами, но без нулевого терминатора \ 0. «NILL» - это константная строка, которая имеет нулевой терминатор, который неявный, но не показан, например, «NILL \ 0». \ 0 является управляющим символом , который используется для обозначения конца строки. Тогда у вас будет индекс за пределами границ при доступе к 3-му элементу массива имен, когда ваш размер массива равен 3.

Чтобы помочь вам найти другие части, которые могут работать неправильно, вот несколько ссылок на функцию, которую вы используете.

зЬгср
StrLen

strcpy скопирует всю строку из одного буфера в следующий, включая управляющий символ нулевого терминатора.

Strlen возвратит количество символов между началом строки и завершающим нулевым символом . Хотя это не будет считать нулевой символ как символ. Вот почему вы увидите предложения с strlen (строка) +1 для включения нулевого терминатора.

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

0 голосов
/ 21 января 2010

Это скорее C, чем C ++ код. Существует эквивалент C ++:

#include <string>
#include <iostream>

class person
{
    std::string name_;
public:
    person();
    //preferable design is to set object invariant in appropriate constructor
    explicit person(const std::string &name);
    std::string get_name() const;
    void set_name(const std::string &name);
    void print()const;
};
person::person()
 : name_("NILL")
{}

person::person(const std::string &name)
: name_(name)
{}

std::string person::get_name() const
{
    return name_;
}

void person::set_name(const std::string &name)
{
    name_ = name;
}
void person::print()const
{
    std::cout<<"Name: "<<name_<<std::endl;
}

int main()
{
    person person1;
    person1.set_name("Zia ur Rahman");
    person1.print();

    //this is better design decision
    //because after constructor we have valid object
    person person2("Zia ur Rahman");
    person2.print();
    std::cin.get();
    return 0;
}
0 голосов
/ 21 января 2010

Предположим, s имеет 5 символов. Затем new char[strlen(s)]; выделяет память из 5 символов. Тогда p[strlen(s)]='\0' эквивалентно p[5]=0. Это очень очень плохо. p[5] не существует.

void person::setstring(const char* s, char*p) 
{ 
if(s!=NULL) 
{ 
delete[] p; 
p=new char[strlen(s)]; 
strcpy(p,s); 
p[strlen(s)]='\0';    //<<<< LOOK! Out of range
} 
} 
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...