创建自定义类型对象的向量

时间:2014-08-11 16:48:28

标签: c++ vector

当我尝试编译我编写的这段代码时,我遇到了一些非常令人困惑的编译错误。想法是创建一个对象“分子”,它具有“原子”类型的向量。从包含原子的x,y,z坐标及其Z值的文件中读取每个原子。这是我的代码示例。我已将我的错误追溯到向量,因此我将在下面显示与之关联的所有代码。该程序有点大,它在没有Atom类之前工作(我实现了原子向量来替换在分子类中保持几何的嵌套数组,我试图学习如何使用向量)。

我将矢量初始化为分子类的私有成员,名称为atoms,类型为Atom,

class Molecule {
private:
     std::vector<Atom> atoms;
     // other declarations to follow
 } 

然后在分子类的构造函数中,我从文件中读取原子数,并将我的矢量原子调整为该数字

 file.open("geom.dat", ios::in);


 if(file.is_open())
{
    file >> natom;
    atoms.resize (natom);

然后继续读取同一个文件,在文件的每一行向向量添加一个原子。

    while(!file.eof())
    {
        int a;
        double b,c,d;

        file >> a >> b >> c >> d;
        Atom A(a,b,c,d);
        atoms.push_back(A);
    }

我编译时收到的错误看起来像是乱码,他们引用的是我没写过的代码行。这是一个例子

 In file included from molecule.cpp:3:
 In file included from /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../lib/c++/v1/iostream:38:
 In file included from /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../lib/c++/v1/ios:216:
 In file included from /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../lib/c++/v1/__locale:15:
 In file included from /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../lib/c++/v1/string:439:
 In file included from /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../lib/c++/v1/algorithm:627:
 /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../lib/c++/v1/memory:1456:36: error: no matching
 constructor for initialization of 'Atom'
            ::new ((void*)__p) _Tp();

我的向量声明或填充方式是否有问题。如果向量不是我编译错误的来源,我可以发布更多代码,但这是我改变的唯一一方。

如要求Atom类: 头文件:

class Atom 
{
private:
    int Zval;
    double x;
    double y;
    double z; 

public:
    Atom(int zv, double xcart, double ycart, double zcart);
    ~Atom();
    int get_Zval();
    double get_x();
    void ch_x(double val);
    double get_y();
    void ch_y(double val);
    double get_z();
    void ch_z(double val);

};

和atom类的源文件:

Atom::Atom(int zv, double xcart, double ycart, double zcart)
: Zval(zv), x(xcart),y(ycart), z(zcart)  { }
int Atom::get_Zval(){   return Zval;    }

double Atom::get_x() {  return x;   }

void Atom::ch_x(double val) {   x+= val;    }

double Atom::get_y(){   return y;   }

void Atom::ch_y(double val) {   y+= val;    }

double Atom::get_z() {  return z;   }

void Atom::ch_z(double val) {   z+= val;    }

3 个答案:

答案 0 :(得分:6)

编译器正在Atom类中查找默认构造函数,但它没有默认构造函数。需要默认构造函数的原因是因为这一行:

atoms.resize (natom);
如果新大小大于当前大小,

resize()会向向量添加新元素,并且这些新元素是默认构造的。

你真正想要的是reserve()

atoms.reserve (natom);

它只是为存储元素分配内存,但实际上并没有添加任何元素。如果您使用resize(),则最终会在输入文件中添加两次两个原子 - 一半是默认构造的,与文件数据无关,另一半是值 - 从文件数据构建。

或者,只需完全删除resize() / reserve(),然后在需要时让push_back()重新分配矢量。但由于您事先知道添加了多少原子,reserve()是一件好事,因为向量只需要分配一次(除非您在加载文件后添加更多原子)。

答案 1 :(得分:0)

您显然已经解决了您发现的问题。现在让我帮你解决一个你还没有意识到的问题。

我发现你当前的设计存在两个相当严重的问题。首先,你的Molecule类对Atom类的内部细节了解得太多(特别是如何从文件中读取Atom数据)。其次,你的分子类是从它的ctor中的文件中读取分子,但是从文件读取数据应该真正发生在流提取器中。

我的结构更像这样:

class Atom { 
    int Zval;
    double x, y, z;
public:
    Atom() : Zval(0), x(0), y(0), z(0) {}

    friend std::istream &operator>>(std::istream &is, Atom &a) { 
        return is >> Zval >> x >> y >> z;
    }
};

class Molecule { 
    std::vector<Atom> atoms;
public:

    friend std::istream &operator>>(std::istream &is, Molecule &m) { 
       int size;
       is >> size;
       atoms.reserve(size);
       std::copy_n(std::istream_iterator<Atom>(is), 
                   size, 
                   std::back_inserter(atoms));
       return is;
    }
};

这样,有关如何从文件中读取Atom的详细信息保留在Atom类中。 Molecule类仅处理Atoms读取大量原子读取的程度,然后读取那么多原子。

至于你如何使用它,你会读到一个类似的分子:

std::ifstream in("Molecule.txt");

Molecule m;

in >> m;

关于它正在做什么以及为什么:Molecule的提取操作符(operator>>)从文件中提取分子的数据。它通过读取计数,然后从文件中读取该数量的原子来实现。 Atom的提取操作符只是从文件中提取一个Atom的数据,然后返回。

在这两种情况下,它们都遵循返回对istream本身的引用的标准约定,因此调用代码可以在调用后检查流的状态,或者将任意数量的提取串起来,如file >> a >> b >> c;

答案 2 :(得分:-2)

根据cplusplus.com,向量包含项目的副本。您需要声明一个公共拷贝构造函数来允许它,并且需要一个默认构造函数来允许内存分配。看起来它正在抱怨后者。

要解决此问题,make sure to follow the Rule Of Three

通过将现有构造函数声明更改为以下内容,可以轻松完成此操作:

//For the default constructor
Atom(int zv=0, double xcart=0, double ycart=0, double zcart=0);

编辑:复制构造函数看起来像编译器可以解决它。抓一下我对此的评论并添加copy assign&amp; dctor