如何在类中使用不同类的对象填充向量

3
我是一名有用的助手,可以为您翻译文本。

我正在开发一个项目,需要创建一个工人类(包含一些基本信息),并将它们全部放入向量中。

我已经找到了适合我的解决方案,但我很好奇是否有更好的方法来完成这个任务?因此,我想寻找不同的代码实现。

这是我的代码:

#include<iostream>
#include<vector>
#include<string>
#include<iterator>

class worker
{
  private:
    std::string _name;
    int _age;
    double _pay;
  public:
    worker() : _age{0}, _pay{0.0} {}
    worker(std::istream& entry){ input(entry); }

    std::istream& input(std::istream& x){ return x >> _name >> _age >> _pay ; }

    const std::string& get_name() { return _name; }
    const int& get_age(){ return _age; }
    const double& get_pay(){ return _pay;}
};

class vecworkers
{
  private:
    std::vector<worker> vec_workers;
  public:
    void input(std::istream& x)
    {
      worker temp;
      while(temp.worker::input(x))
      vec_workers.push_back(temp);

    }

    void output(std::ostream& x)
    {
      worker temp;
      for( std::vector<worker>::const_iterator it = vec_workers.begin() ; it != vec_workers.end() ; ++it )
      {
        temp = *it ;
        std::cout << temp.get_name() << " "<< temp.get_age() << " " << temp.get_pay() << std::endl;
      }
    }

};

int main()
{
  vecworkers w1;
  w1.input(std::cin);
  w1.output(std::cout);
  return 0;
}

非常感谢您能提供的任何帮助。


2
你为什么要将方法命名为“input”和“output”,而不是重载“<<”和“>>”运算符呢?“vecworkers”类的目的是什么?我是说,仅仅为了在一个琐碎简单的循环中读取和写出数据,这样做相当无意义。 - mcserep
@CMate,我刚试着让我的问题尽可能易读。Vecworkers类还有其他功能,但我只是询问这个问题。 - cppdisp
这将是一个很好的问题,适合于codereview.stackexchange.com。 - ChrisWue
4个回答

2

编辑 1:您的问题标题有点误导性


答案:

好的,既然您标记了C++11,我假设我可以在这里使用C++11功能...所以:

关于您的代码的一些建议:

  • The getters in worker class returns const reference, should be marked const functions, so you have:

    const std::string& get_name() const { return _name; }
    const int& get_age() const { return _age; }
    const double& get_pay() const { return _pay;}
    
  • Again, theres no point returning a const int& and const double&, (though I believe optimizers will figure this out).

    const std::string& get_name() const { return _name; }
    int get_age() const { return _age; }
    double get_pay() const { return _pay;}
    
  • You may want to think about overloading the insertion and extraction operators << and >> for worker. It conveys the message.

  • Other than ending the input loop, how do you handle istream failures based on wrong formatting? You may want to think about that. Even without failures, a single wrong formatting will screw up inputs of your entire vecworkers

  • 第一种替代方案(没有设计改变,只是清理...但请记住,您必须进行上述const更正才能使其工作):

class vecworkers
{
  private:
    std::vector<worker> vec_workers;
  public:
    void input(std::istream& x)
    {
        for(worker w; w.input(x); vec_workers.push_back(w));
    }

    void output(std::ostream& x)
    {
        for(const auto& w : vec_workers)
            std::cout << w.get_name() << " " << w.get_age() << " " << w.get_pay() << std::endl;
    }

};
  • 第二种选择(将打印责任移动...或者如果您要使用不同的样式,您可能需要一个负责打印的类)

class worker
{
  private:
    std::string _name;
    int _age;
    double _pay;
  public:
    worker() : _age{0}, _pay{0.0} {}
    worker(std::istream& entry){ input(entry); }

    std::istream& input(std::istream& x){ return x >> _name >> _age >> _pay ; }
    std::ostream& output(std::ostream& x) const { return x << _name << _age << _pay; }

    const std::string& get_name() const { return _name; }
    int get_age() const { return _age; }
    double get_pay() const { return _pay;}
};

class vecworkers
{
  private:
    std::vector<worker> vec_workers;
  public:
    void input(std::istream& x)
    {
        for(worker w; w.input(x); vec_workers.push_back(w));
    }

    void output(std::ostream& x)
    {
        for(const auto& w : vec_workers)
            w.output(std::cout);    //since you didn't overload insertion operator <<
    }

};

  • 第三种选择? 这很容易组合...所以,稍微清理一下你的解决方案就可以工作了。

谢谢!这正是我正在寻找的! - cppdisp
这是一个菜鸟错误,返回const int&和const double&是没有意义的,我同意这一点。感谢建议将getter设置为const函数,我知道它的意思,但没想到在那里使用它。我只是练习,所以在Linux上使用ctrl+d来结束循环。谢谢指出输入流失败问题,我没有考虑过这个问题,但这确实是一个有趣的问题需要解决。你能解释一下这个for循环吗(或者它叫什么?),因为我之前没有遇到过:for(worker w; w.input(x); vec_workers.push_back(w)); - cppdisp
1
@cppdisp,欢迎。至于循环...请参见:http://en.cppreference.com/w/cpp/language/for ... 第一部分只执行一次。第二部分始终被执行并作为布尔值进行测试,如果测试结果为false,则退出循环。(istream可以作为布尔值进行测试)。第三部分始终被执行.... - WhiZTiM
好的,我不知道 istream 可以作为布尔值进行测试。谢谢! - cppdisp

1
我因个人原因更喜欢使用指针进行编程,这超出了您问题的范围。
要简单地“添加”另一个类的对象(有点误导性),请决定您的向量是要拥有这些对象、持有对它们的引用还是指针。
在您的实现中,您创建一个对象,然后将其复制到向量中。
worker temp;
while(temp.worker::input(x))
vec_workers.push_back(temp);

持有指针是一种不同的方法:
auto tmp = std::unique_ptr<worker>(new worker(x));
vec_workers.push_back(std::move(tmp));

在这里,您只需在堆上分配一次内存,并保存指向它的指针(向量拥有该指针)。使用共享/智能指针的方法基本相同。

引用稍微棘手一些,需要使用 std::reference_wrapper

您也可以立即将对象复制到向量中。

workers.push_back(std::move(worker(x));

或者使用原始指针 std::vector<worker*> workers;


感谢您的建议。就您提出的第一个解决方案,由于我在堆上分配了内存,应该如何修改析构函数(是否需要修改)?作为初学者,据我所知,对于每个 new 都必须有一个 delete... - cppdisp
1
如果使用std::unique_ptr,您就不需要使用new运算符。如果没有智能指针而使用new运算符,则需要使用delete,但也可以使用堆栈指针。删除(手动内存管理)可以采用许多形式,例如std::for_each(v.begin(), v.end(), std::default_delete<Type>()); - Ælex

0

我看到这里,这些对象并不是不同的类,或者我弄错了。

它们可能具有不同的构造函数,但仍然不是不同的类。

对于一种类型使用特定的向量类有点无用,但我认为更易读。

你无法创建多个类的向量,因为由于向量语法的限制不可能实现。

正如您所看到的,您可以使用以下方式声明向量

    vector <type>

, not

    vector <type,...>

因此,您只能拥有单一类型的向量。

此外,如果您可以创建多个类的向量,那么它将会破坏大小,因为它将根据放入其中的对象类别而以不同的数量增加。


0

您需要使用多态性和继承来使其工作。不同类型的对象在技术上不能添加到向量中,但是继承和多态性可以使其看起来像是可以的。

因此,您可以像这样拥有一个向量

vector<BaseClass*> vec;

并将派生类的对象推送到其中。许多现代编程语言都有所有类都派生自一个共同的“对象”类,以使这种操作和其他操作成为可能。


看起来你误解了我的意思。向量vec_workers将仅填充类型为worker的对象。我只是在寻找代码的不同实现方式。抱歉让你产生了误导,我会编辑我的问题以使其更加清晰明了。 - cppdisp

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接