C ++类,面向对象编程

时间:2010-01-21 10:24:02

标签: c++ oop

我有一个名为person的非常简单的类,下面给出,我只有两个函数的问题,即setstring()函数和setname()函数,我从setname函数调用setstring()函数。 唯一的问题是在我写的主要功能中 Object.setname(“齐亚”);
结果没问题,如输出屏幕所示, 现在我写的时候 Object.setname(“Zia ur Ra​​hman”);
没有显示任何内容,因为您可以看到输出屏幕。

我知道问题是当我将名称指针传递给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");
}

alt text http://img264.imageshack.us/img264/8867/inheritanceimage004.jpg

alt text http://img263.imageshack.us/img263/3770/inheritanceimage003.jpg

6 个答案:

答案 0 :(得分:3)

如果你想在C ++中进行正确的面向对象编程,你应该远离直接指针管理但是使用STL string class并使用references而不是指针。然后你应该有一个更容易的时间,你的来源应该产生正确的输出。

否则检查person类的构造函数,name-array只有3个元素,但你在那里引用第4个元素(索引0-2!)。同样在setstring()方法中,你没有为数组中的尾部'\ 0'分配足够的空间!

答案 1 :(得分:3)

没有打印任何内容的具体原因是在setstring中,p是名称指针的副本,而不是对它的引用。尝试将setstring的签名更改为:

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

(请注意&)。

请参阅代码中其他重要错误的其他答案 - 除非这些问题得到解决,否则您可能会遇到崩溃或奇怪的行为。

除非代码的目的仅仅是学习动态数组,否则请使用std::string: - 。

答案 2 :(得分:2)

您是否考虑过使用STL中的std :: string?

虽然我看到的第一个问题是这个。

人::人()
{
name = new char [3];
的strcpy(名字, “NILL”);
名称[3] = '\ 0';
}

你分配一个char数组,数组的大小是3个字符,然后你用strcpy复制“NILL”,所以你用数据填充所有字符但没有null终结符\ 0。 “NILL”是一个常量字符串,因此具有隐式但未显示的空终止符,例如“NILL \ 0”。 \ 0是control character,用于表示字符串的结尾。当你访问name数组的第3个元素时,当你的数组大小是3时,你有一个超出范围的索引。

为了帮助您找出可能出错的其他部分,以下是您使用该功能的一些链接。

strcpy
strlen

strcpy会将整个字符串从一个缓冲区复制到下一个缓冲区,包括空终止符控制字符。

Strlen将返回字符串的开头和终止 null字符之间的字符数。虽然它不会将空字符计为字符。这就是为什么你会看到strlen(string)+1的建议,以包含空终止符。

虽然你做得很好,但是在使用标准库函数时你会理解这些小问题。

答案 3 :(得分:2)

首先:

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

name有三个元素 - 你将它视为五个元素。以类似的方式:

p=new char[strlen(s)];

应该是:

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

事实上,这个功能是完全错误的 - 你应该将字符串复制到'name',而不是神秘的'p'参数。如果你真的想要那个函数,那么'p'必须是指向指针或指针引用的指针。

答案 4 :(得分:0)

假设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
} 
} 

答案 5 :(得分:0)

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