对象指针,一般帮助和混乱传染媒介

时间:2011-06-28 05:42:21

标签: c++ pointers object vector

做一个家庭作业,我应该创建一个指向对象的指针向量

稍后在负载下,我将使用继承/多态来扩展课程,包括为期两天的交付,第二天的空中等费用。但是,这不是我现在关注的问题。当前程序的最终目标是打印出向量中的每个对象的内容(名称和地址),并找出它的运费(重量*成本)。

我的麻烦不在于逻辑,我只是​​对与对象/指针/向量相关的几个点感到困惑。但首先是我的代码。我基本上删除了现在没有的东西,int main,将有用户输入,但是现在我硬编码了两个例子。

#include <iostream>
#include <string>
#include <vector>
using namespace std;

class Package {
public:
    Package(); //default constructor
    Package(string d_name, string d_add, string d_zip, string d_city, string d_state, double c, double w);
    double calculateCost(double, double);
    ~Package();

private:    
    string dest_name;
    string dest_address;
    string dest_zip;
    string dest_city;
    string dest_state;
    double weight;
    double cost;

};

Package::Package()
{
    cout<<"Constucting Package Object with default values: "<<endl;
    string dest_name="";
    string dest_address="";
    string dest_zip="";
    string dest_city="";
    string dest_state="";
    double weight=0;
    double cost=0;
}
Package::Package(string d_name, string d_add, string d_zip, string d_city, string d_state, string r_name, string r_add, string r_zip, string r_city, string r_state, double w, double c){

    cout<<"Constucting Package Object with user defined values: "<<endl;
    string dest_name=d_name;
    string dest_address=d_add;
    string dest_zip=d_zip;
    string dest_city=d_city;
    string dest_state=d_state;
    double weight=w;
    double cost=c;
}
Package::~Package()
{
    cout<<"Deconstructing Package Object!"<<endl;
    delete Package;
}
double Package::calculateCost(double x, double y){
    return x+y;
}
int main(){
    double cost=0;
    vector<Package*> shipment;
    cout<<"Enter Shipping Cost: "<<endl;
    cin>>cost;
    shipment.push_back(new Package("tom r","123 thunder road", "90210", "Red Bank", "NJ", cost, 10.5));
    shipment.push_back(new Package ("Harry Potter","10 Madison Avenue", "55555", "New York", "NY", cost, 32.3));
    return 0;

}

所以我的问题是:

  1. 我被告知我必须使用矢量 对象指针,而不是对象。 为什么?我的任务需要它 特别是,但我也告诉过它 否则不会起作用。
  2. 我应该在哪里创建这个 向量?     它应该是我的包的一部分     类?我该如何添加     对象呢?
  3. 我需要复制构造函数吗?为什么呢?

  4. 什么是解构的正确方法 我的对象指针向量?

  5. 任何帮助将不胜感激。我在这里搜索了很多相关的文章,我意识到我的程序会有内存泄漏。使用boost ::中的一个专门的ptrs将无法供我使用。现在,我更关心的是建立我的程序的基础。这样我就可以实现我需要创建的功能。

    感谢。

3 个答案:

答案 0 :(得分:6)

指针向量可以重用于存储子类的对象:

class Person
{
    public:
    virtual const std::string& to_string () = 0;
    virtual ~Person () { } 
};

class Student : public Person
{
   const std::string& to_string ()
   {
       // return name + grade
   }
};

class Employee : public Person
{
   const std::string& to_string ()
   {
      // return name + salary
   }
};

std::vector<Pointer*> persons;
person.push_back (new Student (name, grade));
person.push_back (new Employee (name, salary));
person[0]->to_string (); // name + grade
person[1]->to_string (); // name + salary

理想情况下,矢量应该包含在一个类中。这使内存管理更容易。它还有助于在不破坏现有客户端代码的情况下更改支持数据结构(此处为std::vector):

class PersonList
{
   public:
   Person* AddStudent (const std::string& name, int grade)
   {
       Person* p = new Student (name, grade);
       persons.push_back (p);
       return p;
   }

   Person* AddEmployee (const std::string& name, double salary)
   {
       Person* p = new Employee (name, salary);
       persons.push_back (p);
       return p;
   }

   ~PersonList ()
   {
      size_t sz = persons.size ();
      for (size_t i = 0; i < sz; ++i)
          delete persons[i];
   }

   private
   std::vector<Person*> persons;
};

因此我们可以将代码重写为:

{
   PersonList persons;
   Person* student = persons.AddStudent (name, grade);
   Person* employee = persons.AddEmployee (name, salary);
   student.to_string ();
   employee.to_string ();
} // The memory allocated for the Person objects will be deleted when
  // `persons` go out of scope here.

熟悉Rule of Three将帮助您决定何时将复制构造函数添加到类中。另请阅读const correctness

答案 1 :(得分:2)

问题1: 你提到了继承。由于继承的对象通常需要更多的存储字节,因此它们不适合基础对象的位置。如果您尝试将它们放入,则会获得基础对象。这称为对象切片。

问题2: 在编写代码之前先设计。有很多可能的解决方案。 首先,您可以将其保存在main()中,但稍后您将被迫创建类似PackageContainer的类来保存对象。

问题3 + 4: 当一个类对象拥有动态分配的对象(三巨头的规则)时,你需要一个复制构造函数,一个赋值运算符=和一个析构函数。所以PackageContainer可能需要它们。 您可以使用new Object(..)动态创建对象。在你的指针向量被破坏之前,你有责任销毁它们并将它们的记忆带回系统:

for (size_t i = 0; i < shipment.size(); ++i)
{
  delete shipment[i];
}

由于使用裸指针来动态分配对象是不安全的,请考虑使用

std::vector<tr1::shared_ptr<Package> > shipment;

代替或

std::vector<std::shared_ptr<Package> > shipment;

如果您的编译器理解C ++ 0x。 shared_ptr处理为你释放内存:它为一个对象指针实现了三巨头规则。它应该用于生产质量代码。

但是也尝试用赤裸的指针来纠正它。我认为这就是你的家庭作业。

答案 2 :(得分:1)

我被告知我必须使用对象指针的向量,而不是对象。为什么?我的任务专门要求它,但我也被告知它不会起作用。

通常,人们会避免使用对象向量来避免 Object Slicing 的问题。使多态性工作你必须使用某种指针。我不确定你的赋值中的类是如何对齐的,但是你可能在那里有继承,因此如果vector存储Base类的对象并且你在其中插入Derived类的对象,那么它将导致派生类成员切片关闭。

最佳解决方案是使用智能指针而不是Raw指针。 STL有一个auto_ptr,但不能在标准容器中使用。智能指针是最好的解决方案,但正如你已经说过的,你不能在你的情况下使用Boost So,你可以使用编译器的实现智能指针,它位于TR1命名空间中,但请记住,TR1函数的命名空间存在一些分歧(Visual C ++将它们放在std::中,而GCC将它们放在std::tr1::中)。

我应该在哪里创建此向量?它应该是我的Package Class的一部分吗?我该如何添加对象呢?
您的示例代码已经有一个向量中添加指向Package类的指针的示例。简而言之,您将动态分配指向Package的指针,然后将它们添加到向量中。

我需要复制构造函数吗?为什么?
编译器生成的复制构造函数执行成员复制。有时这还不够。例如:

class MyClass {
    public:
        MyClass( const char* str );
        ~MyClass();
    private:
        char* str;
    };

    MyClass::MyClass( const char* str2 )
    {
        str = new char[srtlen( str2 ) + 1 ];
        strcpy( str, str2 );
    }

    Class::~Class()
    {
        delete[] str;
    }

在这种情况下,str成员的成员复制不会复制缓冲区(只会复制指针(shallow copy)),因此第一个被销毁的副本共享缓冲区将调用delete[]成功,第二个会遇到Undefined Behavior。在这种情况下,您还需要deep copying copy constructor(以及赋值运算符)。

何时使用自定义副本构造函数最好由 Rule Of Three 定义:

Whenever you are writing either one of Destructor, Copy Constructor or Copy Assignment Operator, you probably need to write the other two.

解构对象指针向量的正确方法是什么?
您必须在每个包含的指针上显式调用delete以删除它指向的内容。

vector::erase
从向量容器中删除并调用其析构函数,但如果包含的对象是指针,则它不会取得破坏它的所有权。

在此处查看this answer,了解如何正确删除指向对象的指针向量。