正向声明和动态分配该声明类的指针数组

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

本文关键字:声明 指针 数组 动态分配      更新时间:2023-10-16

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

源文件中类声明的顺序是InventorySystem、InventoryItem、Product、eProduct。由于InventorySystem包含InventoryItem指针数组,您必须在InventoryItem上使用正向声明

因此InventoryItem->Product->eProduct在派生继承中相互关联,我们的任务是将该继承与InventorySystem类相结合来管理指向eProduct对象的指针数组。

不幸的是,我所有的StackOverflow帖子都让我得出了这样的结论:对我的要求是不可能的。正如我所理解的正向声明,"只有通知编译器类的存在才是真正有用的",任何与代码的结构或定义有关的上下文都不适用于正向声明——这似乎与我实验室的其他要求直接冲突,因为InventorySystem需要一个名为BuildInventory的方法,该方法解析格式化的文本文件并动态分配指向eProduct对象的指针数组。这不需要"正向声明"对象的构造函数吗?

我真的,真的希望我只是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 filen";
        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;
}

这个秘密在教授给你的指令中,也在你自己的描述中:

源文件中类声明的顺序是InventorySystem、InventoryItem、Product、eProduct。由于InventorySystem包含InventoryItem指针数组,您必须在InventoryItem上使用正向声明

我们的任务是编写与InventorySystem类相结合的继承结构,以管理指向eProduct对象的指针数组

所以你需要这样的东西:

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类声明内部实现BuildInventory()inline,因为eProduct类尚未声明。BuildInventory()的实现需要在定义了eProduct之后进行分离和实现,例如:

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文件)来完成的,例如:

库存.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需要一个名为BuildInventory的方法,该方法解析格式化的文本文件并动态分配指向eProduct对象的指针数组。这不需要"正向声明"对象的构造函数吗?

回答

是的,这需要eProduct的完整类定义以及从InventoryItem派生的任何其他叶级类。然而,这是在类的实现中。

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

正向声明允许您指定正向声明类型的指针和引用,也可以在函数声明中使用该类型(在返回类型和参数类型中)。的确,正向声明不允许您实际实例化类型,例如作为局部变量或类属性,因为它还不是一个完整的类型(称为不完整类型),但前提是这不是必需的,您应该能够使其工作。

如果您需要在函数体内部处理类型的实例化,那么这也是完全可行的,前提是您在完全定义依赖类型之后定义实际的函数体。这通常是通过将类定义和函数实现分离为两个独立的源文件来完成的,即标头(.h.hpp)和代码(.c.cpp)。在真正进入代码之前,代码文件需要包括它们所依赖的所有头。

请参阅我什么时候可以使用远期申报?以获得对转发声明可以做什么和不能做什么的出色总结。