转发声明并动态分配声明的指针数组 Class?

Forward Declaring and Dynamically Allocating an Array of Pointers of that Declared Class?

我的 C++ 实验室一整天都遇到这个问题。据我所知,除了我的教授在我们的作业中规定的这个条款外,我的一切正常:

The order of class declarations in your source file is InventorySystem, InventoryItem, Product, eProduct. Since InventorySystem contains InventoryItem array of pointers you must use forward declaration on InventoryItem

因此 InventoryItem -> Product -> eProduct 在派生的层次结构中相互关联,我们的任务是编写该层次结构并结合 InventorySystem class 来管理指向 eProduct 对象的指针数组。

不幸的是,我对 Whosebug 帖子的所有翻阅都让我得出这样的结论,即要求我做的事情是不可能的。据我了解前向声明,"it is really only useful to inform the complier that the class exists" 和任何与结构或代码定义相关的内容都不适用于前向声明——这似乎与我实验室的其他要求直接冲突,因为 InventorySystem 有一个方法需要调用 BuildInventory,它解析格式化的文本文件并动态分配指向 eProduct 对象的指针数组。那不需要 "forward declared" 对象的构造函数吗?

我真的,真的希望我只是 C++ 的新手,我被大量误导了,因为这个问题让我一整天都快抓狂了。

在此先感谢您的帮助。

PS:对于函数名和变量的奇怪大小写感到抱歉,我的教授在我们的作业中就是这样写的,我认为只使用他建立的东西更安全。

//Format for text file is Name;Quantity;Price;Condition
void BuildInventory()
{
    ifstream fin ("in.txt");

    string     name="";
    string     Buffer = "";
    int        quantity = 0;
    double     price = 0.0;
    int        temp = 0; 
    if (!fin) {
        cout << "ERROR: Failed to open input file\n";
        exit(-1);
    }

    while ( getline (fin, Buffer, ';') ) {
        string      condChar = "";
        Condition   condition = NEW;

        name = Buffer;
        getline (fin, Buffer, ';');
        quantity = atol (Buffer.c_str ( ) );   
        getline (fin, Buffer, ';');
        price = atof (Buffer.c_str( ) );  
        getline (fin, Buffer, '\n') ; 
        condChar = Buffer.c_str();

        if(condChar.compare("R") == 0)
            condition = REFURBISHED;
        else if(condChar.compare("U") == 0)
            condition = USED;
        else if(condChar.compare("D") == 0)
            condition = DEFECTIVE;

        ep = new eProduct(name, quantity,  price , condition);
        ItemList[ItemCount] =ep;
        ++ItemCount;

        fin.ignore(1, '\n');
    }
    fin.close();
    Sort();
}

下面是 InventorySystem 动态分配的指针数组必须指向的对象层次结构的构造函数(全部指向 eProducts)

//Constructor of eProduct
eProduct(string Name, int Quantity, double Price, Condition condition)
    :Product(Name, Quantity, Price)
{
    this -> condition = condition;
}
//Constructor of Product
Product():ProductID(0), Price(0.0){}
Product(string Name, int Quantity, double Price)
    :InventoryItem(Name, Quantity)
{
    this -> Price = Price;
    this -> ProductID = generateProductID();
}
//Constructor of InventoryItem
InventoryItem(std::string Name, int Quantity)
{
    this -> Name = Name;
    this -> Quantity = Quantity;
}

秘诀就在你教授给你的指导以及你自己的描述中:

The order of class declarations in your source file is InventorySystem, InventoryItem, Product, eProduct. Since InventorySystem contains InventoryItem array of pointers you must use forward declaration on InventoryItem

our assignment is to write that heirarchy combined with an InventorySystem class to manage an array of pointers to eProduct objects.

所以你需要这样的东西:

class InventoryItem; // forward declaration

class InventorySystem
{
    ...
    InventoryItem* ItemList[TheArraySizeHere]; // array of InventoryItem pointers
    ...
};

class InventoryItem
{
    ...
};

class Product : public InventoryItem
{
    ...
};

class eProduct : public Product
{
    ...
};

由于 eProduct 派生自 InventoryItem,您可以将 eProduct 个指针存储在 InventoryItem 个指针的数组中。

这是另一块拼图。您不能在 InventorySystem class 声明中实现 BuildInventory() inline,因为 eProduct class 尚未声明. BuildInventory()的实现需要在定义了eProduct之后单独实现,eg:

class InventoryItem; // forward declaration

class InventorySystem
{
    ...
    InventoryItem* ItemList[TheArraySizeHere]; // array of InventoryItem pointers
    ...
    void BuildInventory();
};

class InventoryItem
{
    ...
};

class Product : public InventoryItem
{
    ...
};

class eProduct : public Product
{
    ...
};

...

void InventorySystem::BuildInventory()
{
    // implementation here ...
}

这通常是通过将所有 声明 放在 .h 文件中,并将所有 实现 放在.c/.cpp 文件 #include.h 文件,例如:

Inventory.h:

#ifndef InventoryH
#define InventoryH

class InventoryItem; // forward declaration

class InventorySystem
{
    ...
    InventoryItem* ItemList[TheArraySizeHere]; // array of InventoryItem pointers
    ...
};

class InventoryItem
{
    ...
    InventoryItem(std::string Name, int Quantity);
    ...
};

class Product : public InventoryItem
{
    ...
    Product();
    Product(string Name, int Quantity, double Price);
    ...
};

class eProduct : public Product
{
    ...
    eProduct(string Name, int Quantity, double Price, Condition condition);
    ...
};

#endif

Inventory.cpp:

#include "Inventory.h"

//Constructor of InventoryItem
InventoryItem::InventoryItem(std::string Name, int Quantity)
{
    this->Name = Name;
    this->Quantity = Quantity;
}

//Constructor of Product
Product::Product() : ProductID(0), Price(0.0) {}
Product::Product(string Name, int Quantity, double Price)
    : InventoryItem(Name, Quantity)
{
    this->Price = Price;
    this->ProductID = generateProductID();
}

//Constructor of eProduct
eProduct::eProduct(string Name, int Quantity, double Price, Condition condition)
    : Product(Name, Quantity, Price)
{
    this->condition = condition;
}

void InventorySystem::BuildInventory()
{
    // implementation here ...
}

问题

InventorySystem has a method required called BuildInventory that parses a formatted textfile and dynamically allocates an array of pointers to eProduct objects. Does that not require a constructor of the "forward declared" object?

回答

是的,这需要 eProduct 的完整 class 定义以及从 InventoryItem 派生的任何其他叶级别 classes。但是,那是在执行class.

class的定义仍然可以继续使用指针指向转发声明的classes。

A forward-declaration 允许您指定 forward-declared 类型的指针和引用,并且还可以在函数声明中使用该类型(在 return 类型和参数类型中)。 forward-declaration 确实 而不是 允许您实际实例化类型,例如作为局部变量或 class 属性,因为它还不是一个完整的类型(它被称为 不完整的类型 ),但前提是这不是必需的,你应该能够让它发挥作用。

如果您需要在函数 body 中使用类型的实例化,这也是完全可行的,只要您定义实际函数 body after[=24] =] 依赖类型已经完全定义。这通常通过将 class 定义和函数实现分成两个单独的源文件来完成,即 header(.h.hpp)和代码(.c.cpp).在实际进入代码之前,代码文件需要包含它们所依赖的所有 header。

请参阅 When can I use a forward declaration?,了解您可以使用 forward-declaration 做什么和不能做什么的精彩总结。