cpp一些基本问题

发布于 2024-09-02 23:43:01 字数 1232 浏览 3 评论 0原文

我的任务如下: 创建具有 char*name 和 int Age 的 Person 类。使用变量动态分配内存实现构造函数、析构函数、函数 init 和友元函数 show。然后将这个类转化为头文件和cpp文件并在其他程序中实现。好的,这是我的 Person 类:

#include <iostream>
using namespace std;

class Person {   
    char* name;
    int age;
public:   

    Person(){
        int size=0;
        cout << "Give length of char*" << endl;
        cin >> size;
        name = new char[size];      
        age = 0;
    }

    Person::~Person(){
        cout << "Destroying resources" << endl;
        delete [] name;
        delete take_age();
    }  

    friend void show(Person &p);

   int* take_age(){
       return &age;
   }

   char* take_name(){
         return name;      
   }

    void init(char* n, int a) {
        name = n;
        age = a;
    }
}; 

void show(Person *p){
    cout << "Name: " << p->take_name() << "," << "age: " << p->take_age() << endl; 
}

int main(void) {
    Person *p = new Person;  
    p->init("Mary", 25);

    show(p);

    system("PAUSE");
    return 0;
}

现在带有标头/实现部分:
- 我需要在头文件/实现文件中引入构造函数吗?如果是 - 怎么办?
- 我的 show() 函数是一个友好的函数。我应该以某种方式考虑它吗?

我已经未能在考试中返回此任务,但我仍然想知道如何实现它。

My task was as follows :
Create class Person with char*name and int age. Implement contructor using dynamic allocation of memory for variables, destructor, function init and friend function show. Then transform this class to header and cpp file and implement in other program. Ok so here's my Person class :

#include <iostream>
using namespace std;

class Person {   
    char* name;
    int age;
public:   

    Person(){
        int size=0;
        cout << "Give length of char*" << endl;
        cin >> size;
        name = new char[size];      
        age = 0;
    }

    Person::~Person(){
        cout << "Destroying resources" << endl;
        delete [] name;
        delete take_age();
    }  

    friend void show(Person &p);

   int* take_age(){
       return &age;
   }

   char* take_name(){
         return name;      
   }

    void init(char* n, int a) {
        name = n;
        age = a;
    }
}; 

void show(Person *p){
    cout << "Name: " << p->take_name() << "," << "age: " << p->take_age() << endl; 
}

int main(void) {
    Person *p = new Person;  
    p->init("Mary", 25);

    show(p);

    system("PAUSE");
    return 0;
}

And now with header/implementation part :
- do I need to introduce constructor in header/implementation files ? If yes - how?
- my show() function is a friendly function. Should I take it into account somehow ?

I already failed to return this task on my exam, but still I'd like to know how to implement it.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(8

落叶缤纷 2024-09-09 23:43:01

通过从 char * 切换到 std::string 可以解决您的许多问题。你会很高兴你这么做了。

std::string 类负责内存分配、释放以及复制。

如果这是家庭作业,请说服您的教授为初学者使用 std::string 并为指针部分保留 char *。还要提醒您的教授,C++ 语言与 C 语言不同。这是这些领域之一。

Solve many of your issues, by switching from char * to std::string. You'll be glad you did.

The std::string class takes care of memory allocation, and deallocation as well as copying.

If this is homework, convince your professor to use std::string for beginners and save char * for the section on pointers. Also remind your professor that the C++ langauge is different than the C language. This is one of those areas.

残花月 2024-09-09 23:43:01

使用 deletedelete[] 时不需要 *。只需向其提供一个指针变量即可,例如。

delete[] name;

此外,您的 take_age 成员声称返回 int* 但您实际上返回 int 成员本身。如果您想这样做,您需要使用 & 获取会员的地址。正如 @Jerry 所评论的,这不是您想要在这里做的事情。

You don't need a * when using delete or delete[]. Just supply a pointer variable to it eg.

delete[] name;

Also, your take_age member claims to return a int* but you actually return the int member itself. You need to take the address of the member using & if you want to do that. As @Jerry has commented this is not what you want to do here.

手心的温暖 2024-09-09 23:43:01

尽管该网站上的一些人显然认为这是完全可以接受的,但很好的做法(请参阅

恕我直言,这就是您应该采取的第一步。

Although some on this site apparently think it is completely acceptable, good practice (see Can a constructor return a NULL value?), you should really refrain from doing things like stream operations within the constructor of your object. Do that stream reading outside and then call the function with the results.

That is, IMHO, the first step you should take.

傲鸠 2024-09-09 23:43:01

在典型情况下,管理一个指针和动态分配的内存块(例如本例中的名称)对于一个类来说就足够了。因此,Thomas Matthews 是对的:在这种情况下你真的应该使用字符串。如果您要自己处理它,您仍然应该将该责任拆分到它自己的类中,并将该类的对象嵌入到您的 Person 对象中。如果有的话,std::string 已经尝试做太多事情了;你最好做一些少做的事,而不是多做的事。

您的删除应该与您的分配完全匹配。在这种情况下,唯一的分配是:

    name = new char[size];      

所以唯一的删除应该是:

    delete [] name;

friend 函数而言,您通常希望将友元声明放在类定义内,但将函数定义放在类定义之外:

class Person { 
// ...
    friend void show(Person const &);
// ...
};

void show(Person const &p) { 
     // ...
}

还有其他可能性,但这就是总体思路。特别是,朋友从来都不是成员函数。您拥有的是一个名为 show 的(全局)函数的声明和一个完全独立的成员函数的定义——它们碰巧具有相同的名称,但实际上根本不是同一个函数。

这表明了另一点:常量正确性。您将参数作为对 Person 的引用传递。除非它要修改 Person 对象(在这种情况下,show() 似乎是一个糟糕的名称选择),否则它可能应该引用 const 对象。同样的一般思想也适用于 take_age() ——因为它只检索一个值,所以它应该是一个 const 函数:

int take_age() const { return age; }

我可能已经尝试涵盖太多了,所以我暂时闭嘴...

In a typical case, managing a pointer and block of dynamically allocated memory (such as the name in this case) is enough responsibility for one class. As such, Thomas Matthews is right: you should really use string in this case. If you're going to handle it yourself, you should still split that responsibility off into a class of its own, and embed an object of that class into your Person object. If anything, std::string already tries to do too much; you'd be better off with something that does less, not more.

Your deletes should exact match with your allocations. In this case, the only allocation is:

    name = new char[size];      

so the only deletion should be:

    delete [] name;

As far as friend functions go, you normally want the friend declaration inside the class definition, but the function definition outside the class definition:

class Person { 
// ...
    friend void show(Person const &);
// ...
};

void show(Person const &p) { 
     // ...
}

There are other possibilities, but that's the general idea. In particular, a friend is never a member function. What you had was a declaration of one (global) function named show and a definition of a completely separate member function -- that happened to have the same name, but wasn't really the same function at all.

That shows one other point: const-correctness. You were passing the parameter as a reference to Person. Unless it's going to modify the Person object (in which case, show() seems like a poor choice of name), it should probably take a reference to a const object. The same general idea applies to take_age() -- since it only retrieves a value, it should be a const function:

int take_age() const { return age; }

I've probably already tried to cover too much, so I'll shut up for the moment...

万劫不复 2024-09-09 23:43:01

我认为你应该调查你的代码的以下部分(例如,它们下面是什么,这里发生了什么,等等......)

int * take_age(); // You should return plain `int` here, I assume


~Person(){
    cout << "Destroying resources" << endl;
    delete *[] name; // Do you understand why did you put `*` here?
    delete * take_age(); // Do you understand why did you write this? What behaviour you were trying to achieve?

,实际上,等等。我认为,只有当您完成了基本内容后,您才能继续进行标题设计问题和友元函数。

I think you should investigate the following pieces of your code (like, what's beneath them, what happens here, etc...)

int * take_age(); // You should return plain `int` here, I assume


~Person(){
    cout << "Destroying resources" << endl;
    delete *[] name; // Do you understand why did you put `*` here?
    delete * take_age(); // Do you understand why did you write this? What behaviour you were trying to achieve?

And, actually, so on. Only when you're done with the basic stuff, I think, you can move on to header designing questions and friend functions.

彩扇题诗 2024-09-09 23:43:01

首先,感谢您尝试找到正确的方法来实施您的课程,特别是在已经错过答案之后。

从您在顶部的描述来看,我认为您可能误解了这项作业的一些要求。首先,我的解释是设置名称和年龄的值应该在 init() 函数中而不是在构造函数中进行。正如其他几位海报所提到的,您的构造函数应该简单地将您的类初始化为已知的良好状态。例如,

Person() {
    name = NULL;
    age = 0;
}

然后在初始化函数中,您可以分配值。查看原始的 init() 函数,可能应该提到的是,简单地将指针值 (char *) 分配给另一个指针 (char *) 仅复制指针的值,而不是它表示的数据。因此,对于名称值的分配,您需要计算所需缓冲区的大小,分配缓冲区并自行复制数据。基本的 init() 函数可能看起来像

init(const char *n, int a) {
    // Calculate the required name length plus a NULL-terminator
    size_t nameLen = strlen(n) + 1;

    // Free any previous value.
    if (name != NULL) {
        delete[] name;
    }

    // Allocate the name buffer and copy the name into it.
    name = new char[nameLen];
    memcpy(name, n, nameLen);

    // Store the age.
    age = a;
}

最后,在析构函数中,您释放类分配的所有资源,在本例中是名称缓冲区。

~Person() {
    if (name != NULL) {
        delete[] name;
    }
}

如果您有一本书或与您的班级相关的东西,您可能需要查看有关指针的信息。它们可能有点棘手,但学习很重要。我怀疑这就是为什么问题指定使用 char * 作为字符串而不是 STL 字符串类。

对于有关将信息放入头文件和源文件中的问题,通常认为创建包含类声明和成员函数原型的头文件,然后在单独的源文件中提供方法的实现是一种很好的做法。对于一些简单的函数,您可以直接在头文件中提供实现。

在单独的源文件中提供类成员定义时,关键是提供类名以正确确定函数的范围(即 Person::)。因此,您的头文件可能包含类似的类定义

// Header file (e.g., person.h)

class Person {
private:
    char *name;
    int age;

public:
    Person() { name = NULL; age = 0 };
    ~Person() { if (name != NULL) delete[] name; }

    void init(const char *n, int a);

    // Other method declarations and/or definitions
};

,然后在源文件中

// Source file (e.g., person.cpp)

void Person::init(const char *n, int a) {
    // ...
}

// Rest of method definitions

使用您的 person 类的源文件只需要包含带有您的类定义的头文件。

First off, kudos on trying to find the right way to implement your class, particularly after having missed the answer already.

From your description at the top, I think you may have misunderstood some of what was being asked for this assignment. First, my interpretation would be that setting the value of the name and age should take place in the init() function rather than in the constructor. As mentioned by several other posters, your constructor should simply initialize your class to a known-good state. For example,

Person() {
    name = NULL;
    age = 0;
}

Then in your initialization function, you can assign the values. Looking at your original init() function, it should probably be mentioned that simply assigning a pointer value (char *) to another pointer (char *) only copies the value of the pointer, not the data that it represents. Thus, for the assignment of the name value you need to calculate the size of the buffer you need, allocate the buffer, and copy the data yourself. A basic init() function would probably look like

init(const char *n, int a) {
    // Calculate the required name length plus a NULL-terminator
    size_t nameLen = strlen(n) + 1;

    // Free any previous value.
    if (name != NULL) {
        delete[] name;
    }

    // Allocate the name buffer and copy the name into it.
    name = new char[nameLen];
    memcpy(name, n, nameLen);

    // Store the age.
    age = a;
}

Finally, in your destructor you free any resources allocated by your class, in this case the name buffer.

~Person() {
    if (name != NULL) {
        delete[] name;
    }
}

If you have a book or something associated with your class, you may want to review the information on pointers. They can be a bit tricky but are important to learn. I suspect that is why the problem specified using char * for strings rather than the STL string class.

To your question about placing information in header and source files, it is often considered good practice to create a header file that contains the class declaration and member function prototypes and then provide the implementation of your methods in a separate source file. For some simple functions, you can provide an implementation directly in your header file.

The key when providing class member definitions in a separate source file is to provide the class name to properly scope the function (i.e., Person::). So your header file may contain a class definition like

// Header file (e.g., person.h)

class Person {
private:
    char *name;
    int age;

public:
    Person() { name = NULL; age = 0 };
    ~Person() { if (name != NULL) delete[] name; }

    void init(const char *n, int a);

    // Other method declarations and/or definitions
};

And then in your source file

// Source file (e.g., person.cpp)

void Person::init(const char *n, int a) {
    // ...
}

// Rest of method definitions

Source files that use your person class need only include the header file with your class definition.

一场信仰旅途 2024-09-09 23:43:01

我认为你的问题在于这一行:
朋友 void(Person &p);
需要它做什么呢。

我需要在头文件/实现文件中引入构造函数吗?
构造函数可以位于 .h 或 .cpp 文件中。没关系。一般来说,如果函数很短,可以将其包含在 .h 文件中。任何更长的内容都应该放在 .cpp 中。

我的 show() 函数是一个友好的函数。
不确定你的意思是什么。友元函数存在于类定义之外。您的 show 函数是在类内部定义的,因此不需要成为友元。

I think your problem is with this line:
friend void(Person &p);
What is it needed for.

do I need to introduce constructor in header/implementation files ?
The constructor can be in the .h or the .cpp file. It doesn't matter. Generally if the function is short it is ok to include it in the .h file. Anything longer should go in the .cpp.

my show() function is a friendly function.
Not sure what you mean by this. friend functions exist outside the class definition. Your show function is defined inside the class so does not need to be a friend.

闻呓 2024-09-09 23:43:01

除了之前发布的答案之外,我还有两点建议给您:

  • 不要使用“朋友”。这里有些人可能不同意我的观点,但“朋友”确实不应该再成为 C++ 的一部分,因为它违背了 OOP 的含义。
  • 命名你的方法:避免将你的方法命名为“take_name”或“take_age”。按照惯例,由于这些是 getter,请考虑将它们命名为“getName”和“getAge”。通过这种方式,你最终会得到开发人员更多的尊重。

in addition to the previously posted answers, i've got two points of advice for you:

  • don't use 'friend'. some here may disagree with me, but 'friend' should really not be part of C++ anymore as it goes against what OOP stands for.
  • naming your methods: avoid naming your methods like 'take_name' or 'take_age'. conventionally, since those are getters, consider naming them 'getName' and 'getAge'. you end up with much more respect from developers this way.
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文