2011-06-28 35 views
0

都在我应该创建指针的对象矢量对象指针,一般帮助和混乱

后来就停机负载载体的家庭作业,我将使用继承/多态性延长该课程包括两天交付费用,第二天的空气等等。但是,这不是我现在关心的问题。当前程序的最终目标是打印矢量中的每个对象的内容(名称&地址)并查找其运输成本(重量*成本)。

我的麻烦不在于逻辑,我只是​​在与对象/指针/向量相关的一些点上感到困惑。但首先我的代码。我基本上删除了现在不需要的所有东西,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. 什么是解构对象指针的向量的正确方法 ?

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

谢谢。

+0

*附注* Package中的析构函数是错误的,不会被编译。你尝试编译它吗? –

+0

我居然拿出来编译它。在这个代码示例中忘了这么做。 – Staypuft

回答

3

指针的载体可以重复使用,用于存储子类的对象:

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

+0

要将Person用作基类,它应该有一个虚拟析构函数。 – frast

+0

@frast谢谢你指出这一点。代码已更新。 –

1

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

一般,人们将避免使用对象的矢量,以避免Object Slicing的问题。为了使多态性工作你必须使用某种类型的指针。我不确定你的任务中的类是如何对齐的,但可能你会在某处存在继承,因此,如果向量存储基类的对象,并且在其中插入了派生类的对象,那么它会导致派生类成员切片关闭。

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

我应该在哪里创建这个矢量?它应该是我的包类的一部分吗?那么我该如何去添加对象呢?
您的示例代码已经有向矢量中添加指向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知道如何正确地删除指向对象的指针向量。

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为你释放内存:它为一个对象指针实现三大规则。它应该用于生产质量代码。

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

+0

谢谢。也许这只是我的知识在涉及类/对象方面的差距,但我不太确定我的int main()会如何填充类中定义的向量?我不会为每个创建的对象创建另一个矢量吗?另外,使用我的例子,没有一个类要求所有它的成员被传递给它进行构造吗?例如,我传递名称,重量,地址来创建每个对象?我如何/为什么要从int main()传递给它?那么这个载体是否可以在我的课堂上公开访问?谢谢 – Staypuft

+0

@Staypuft:类不需要为所有成员获取构造函数参数,但它应该初始化所有成员以保证有效的对象状态。将数据对象封装到类中时,要将信息放入其中并将其取回,必须设计适合于要表达的访问器和修改器方法。所以main()只接受程序中最高抽象层次的对象。他们互相发送“消息”以实现您的目标。尝试获得一本关于C++的好书,比如Bruce Eckel的“Thinking in C++”。如果你幸运的话,你可以在网上找到一些。 –