将用户输入的数据封装到一个类中

发布于 2024-08-27 20:20:31 字数 744 浏览 9 评论 0原文

对于作业,我编写了一个简单的 C++ 程序,该程序使用一个超类(学生)和两个子类(CourseStudentResearchStudent)来存储学生列表并打印出他们的学生列表详细信息,为两种不同类型的学生显示不同的详细信息(使用覆盖 Student 中的 display() 方法)。

我的问题是关于该程序如何收集用户输入的信息,例如学生姓名、ID 号、单位和费用信息(对于课程学生)以及研究信息(对于研究生):

我的实现会提示用户输入和收集在类本身内处理的输入。这背后的原因是每个类都知道它需要什么类型的输入,因此让它知道如何请求它对我来说是有意义的(给定一个用于请求的 ostream 和一个用于从中收集输入的 istream)。

我的讲师说,提示和输入都应该在主程序中处理,这在我看来有点混乱,并且会使扩展程序以处理不同类型的学生变得更加困难。

作为一种折衷方案,我正在考虑创建一个帮助程序类来处理每种类型的 Student 的用户输入提示和收集,然后由主程序调用。这样做的优点是学生类没有那么多内容(因此它们更干净),而且如果需要输入功能,它们也可以与帮助程序类捆绑在一起。这也意味着可以添加更多的 Student 类,而无需对主程序进行重大更改,只要为这些新类提供辅助类即可。此外,辅助类可以替换为替代语言版本,而无需对类本身进行任何更改。

用户输入的三种不同选项(完全封装、辅助类或在主程序中)的主要优点和缺点是什么?

For an assignment I've made a simple C++ program that uses a superclass (Student) and two subclasses (CourseStudent and ResearchStudent) to store a list of students and print out their details, with different details shown for the two different types of students (using overriding of the display() method from Student).

My question is about how the program collects input from the user of things like the student name, ID number, unit and fee information (for a course student) and research information (for research students):

My implementation has the prompting for user input and the collecting of that input handled within the classes themselves. The reasoning behind this was that each class knows what kind of input it needs, so it makes sense to me to have it know how to ask for it (given an ostream through which to ask and an istream to collect the input from).

My lecturer says that the prompting and input should all be handled in the main program, which seems to me somewhat messier, and would make it trickier to extend the program to handle different types of students.

I am considering, as a compromise, to make a helper class that handles the prompting and collection of user input for each type of Student, which could then be called on by the main program. The advantage of this would be that the student classes don't have as much in them (so they're cleaner), but also they can be bundled with the helper classes if the input functionality is required. This also means more classes of Student could be added without having to make major changes to the main program, as long as helper classes are provided for these new classes. Also the helper class could be swapped for an alternative language version without having to make any changes to the class itself.

What are the major advantages and disadvantages of the three different options for user input (fully encapsulated, helper class or in the main program)?

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

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

发布评论

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

评论(3

暗喜 2024-09-03 20:20:31

正如 scv 所提到的,通常最好将表示(视图)与内部结构(模型)分离。

这里有一个典型的案例:

  • Student 类,模型层次结构的根
  • Displayer 类,另一个独立层次结构的根

显示的问题是它会根据不同的情况而变化两个元素,这需要双重调度系统(使用虚拟)。

传统上,这是使用访问者模式解决的。

让我们先检查一下基类:

// student.h
class Displayer;

class Student
{
public:
  virtual ~Student();
  virtual void display(Displayer& d) const = 0; // display should not modify the model
};

// displayer.h
class Student;
class CourseStudent;
class ResearchStudent;

class Displayer
{
public:
  virtual ~Displayer();

  virtual void display(const Student& s) = 0; // default method for students
                                              // not strictly necessary
  virtual void display(const CourseStudent& s) = 0;
  virtual void display(const ResearchStudent& s) = 0;
};

现在,让我们实现一些:

// courseStudent.h
#include "student.h"

class CourseStudent: public Student
{
public:
  virtual void display(Displayer& d) const;

};

// courseStudent.cpp
#include "courseStudent.h"
#include "displayer.h"

// *this has static type CourseStudent
// so Displayer::display(const CourseStudent&) is invoked
void CourseStudent::display(Displayer& d) const
{
  d.display(*this);
}


// consoleDisplayer.h
#include "displayer.h"

class ConsoleDisplayer: public Displayer
{
public:
  virtual void display(const Student& s) = 0; // default method for students
                                              // not strictly necessary
  virtual void display(const CourseStudent& s) = 0;
  virtual void display(const ResearchStudent& s) = 0;
};

// consoleDisplayer.cpp
#include "consoleDisplayer.h"

#include "student.h"
#include "courseStudent.h"
#include "researchStudent.h"

void ConsoleDisplayer::display(const Student& s) { }

void ConsoleDisplayer::display(const CourseStudent& s) { }

void ConsoleDisplayer::display(const ResearchStudent& s) { }

如您所见,困难的部分是,如果我想添加一个新的 Student 派生类,那么我需要添加一个新的Displayer 中的 virtual 方法,并在 Displayer 的每个派生类中重写它...但除此之外它工作得很好。

优点是显示逻辑现在与模型解耦,因此我们可以添加新的显示逻辑而无需触及模型。

As mentioned by scv, it is normally better to decouple presentation (view) from internal structure (model).

Here you have a typical case:

  • the Student class, root of a model hierarchy
  • the Displayer class, root of another independent hierarchy

The issue with the display is that it varies according to two elements, which calls for a system of double dispatch (using virtual).

This is traditionally solved using the Visitor Pattern.

Let's check the base classes first:

// student.h
class Displayer;

class Student
{
public:
  virtual ~Student();
  virtual void display(Displayer& d) const = 0; // display should not modify the model
};

// displayer.h
class Student;
class CourseStudent;
class ResearchStudent;

class Displayer
{
public:
  virtual ~Displayer();

  virtual void display(const Student& s) = 0; // default method for students
                                              // not strictly necessary
  virtual void display(const CourseStudent& s) = 0;
  virtual void display(const ResearchStudent& s) = 0;
};

And now, let's implement some:

// courseStudent.h
#include "student.h"

class CourseStudent: public Student
{
public:
  virtual void display(Displayer& d) const;

};

// courseStudent.cpp
#include "courseStudent.h"
#include "displayer.h"

// *this has static type CourseStudent
// so Displayer::display(const CourseStudent&) is invoked
void CourseStudent::display(Displayer& d) const
{
  d.display(*this);
}


// consoleDisplayer.h
#include "displayer.h"

class ConsoleDisplayer: public Displayer
{
public:
  virtual void display(const Student& s) = 0; // default method for students
                                              // not strictly necessary
  virtual void display(const CourseStudent& s) = 0;
  virtual void display(const ResearchStudent& s) = 0;
};

// consoleDisplayer.cpp
#include "consoleDisplayer.h"

#include "student.h"
#include "courseStudent.h"
#include "researchStudent.h"

void ConsoleDisplayer::display(const Student& s) { }

void ConsoleDisplayer::display(const CourseStudent& s) { }

void ConsoleDisplayer::display(const ResearchStudent& s) { }

As you can see, the hard part is that if I wish to add a new derived class of Student, then I need to add a new virtual method in Displayer and override it in every derived class of Displayer... but otherwise it works great.

The advantage is that the logic of display is now decoupled from the model, thus we can add new display logic without ever touching our model.

荒岛晴空 2024-09-03 20:20:31

我认为你的老师的意思是“不要把它放在学生班级”。

正如弗拉德提到的,模型是学生班级。该视图不应该出现在学生班级中。这个想法是学生类应该存储有关这些对象的结构信息。如何呈现数据取决于使用该类的事物。例如,如果您稍后要在控制台应用程序和 GUI 应用程序中使用这些类,那么您将不希望在这些类中包含显示代码。这实际上应该取决于使用这些类的应用程序。

视图/控制器将位于辅助类或主程序中。位于主程序中并不意味着它必须是混乱的。您可能有很多函数可以使 main() 看起来漂亮和干净,但如果您将其编写在辅助类中,情况也是如此。您将拥有所有这些功能,也许还有更多。

我的建议是,如果这是一个小练习,请不要添加辅助类,除非您已经清楚地了解该类将如何,或者您有时间花在弄清楚上。

I think that what your teacher meant to say was "don't put it in the Student Classes".

As Vlad mentioned the models would be the student classes. The view should not be in the student classes. The idea is that the student classes should store structural information about those object. How that data is presented is up to the things using the class. If you were, for example, to use these classes later for both a console application and a GUI application, you would not want to have the display code in those classes. That should really be up to the application using the classes.

The view/controller would be in the helper class or the main program. Being in the main program does not mean that it has to be messy. You might have alot of functions to make the main() look nice and clean, but the same would be true if you write it in a helper class. You'll have all those functions and maybe a few more.

What I would suggest is that if this is a small exercise , don't add the helper class unless you already have a clear idea as to how that class would be, or if you have the time to spend on figuring out.

顾挽 2024-09-03 20:20:31

虽然我对我的顾问持怀疑态度,但我认为您的顾问的观点是有道理的。

认识到将 cin/scanf 放入类中的重要性可能过于简单。但想象一下,您的学生班级通过 GUI 构成了一些代码的后端,数据来自各种各样的东西——用于性别的单选按钮、用于年龄组的组合框等等。你真的不应该把所有这些都放在你的学生班级中。

拥有一个“查看器”或一个填充学生的辅助类会有所帮助。我建议根据不同的观点分别开设一堂课。您可以在 main 中执行此操作,但拥有单独的查看器类将帮助您重用代码。

阿尔潘

While I am genetically skeptical to my advisors, I think your advisor has a valid point here.

It might be too simplistic to realize how putting cin/scanf inside classes matter. But imagine this, your student class forms the back-end of some code with a GUI and the data comes from all sorts of things -- radio buttons for gender, combo boxes for age-group and so on. You really should not put all of this inside your student class.

Having a 'viewer' or a helper class that populates student helps. I suggest have a class each depending on the kind of view. You could do it inside main, but having separate viewer classes will help you re-use code.

Arpan

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文