0

我在正确构建一个容器时遇到问题,该容器存储不同类型的类样本,这些类样本都是单个抽象类的继承者。寄存器(容器)存储指向这些样本数组的指针,该数组具有抽象类的类型。每当我尝试访问样本中包含的数据时,我只能成功地检索到也可以在基类中找到的部分。例如,在包含所有三个继承者的元素的寄存器上使用的重载 <<,只会在屏幕上写入抽象类部分,并且会忽略不存在的任何内容。现在我真的不知道问题是否在于打印出其他正确存储的元素,或者存储已经以不适当的形式完成,所以这将是我的问题:应该如何正确完成?这是代码:

class Register{
private:
int elementNum;
type * pData;
friend std::ostream &operator<<(std::ostream & os,const Register &v);
};
class type{
int a;
int b;
};
class type2: public type{
int c;
int d;
};

其他两个继承者的行为与 type2 相同。这是主要的一部分:

    int main ()
    {
        type2 A1(1,2,3,4);
        type3 D1(4,5,6,7,8);
        type4 H1(9,10,11,12,13);
        std::cout<<A1<<D1<<H1<<endl;
        Register R1;
        R1.Add(0,A1);
        R1.Add(1,D1);
        R1.Add(2,H1);
        R1.Display();
        R1.MaxLength();
        std::cout<<R1;
        return 0;
    }

寄存器上的运算符<<:

std::ostream &operator<<(std::ostream & os,const Register &v){
    for(int i=0;i<v.elementNum;i++)
    {
        os<<v.pData[i]<<endl;
    }
    return os;
}

仅使用 << 运算符或寄存器中的函数会解决此问题。编辑:添加功能的实现:

void Register::Add(int position,type& T){
    if(position<0||position>elementNum+1)
        return;
    type *pTemp = new type[elementNum+1];
    if(elementNum==0)
    {
        pTemp[0]=T;
        delete[]pData;
        pData=pTemp;
    }
    else
    {
        for(int i=0,j=0;j<elementNum+1;i++,j++)
        {
            if(position!=j)
                pTemp[j]=pData[i];
            else
            {
                i--;
                pTemp[j]=a;
            }
        }
        delete[]pData;
        pData=pTemp;
    }
    elementNum++;
}
4

2 回答 2

1

您只能以多态方式访问基类共有的公共成员或基类可用的虚拟方法。

此外,您只能通过指针/引用访问虚拟方法,并且通常不能像尝试使用pData.

如果您创建一个virtual std::ostream &type::dump(std::ostream &os)成员方法并覆盖在type2等,您可以让每个覆盖的方法显示特定于其子类型的内容。

struct type {
  virtual ostream &dump(ostream &os) {
    os << a << " " << b << " ";
    return os;
  }
  int a;
  int b;
};

struct type2 : type {
  // Can use parent implementation AND use subtype-specific members:
  ostream &dump(ostream &os) override {
    type::dump(os);
    os << c << " " << d << " ";
    return os;
  }
  int c;
  int d;
};

// This class needs new "void Add(int pos, type &)" logic.
struct Register {
  int   elementNum;
  type *pData; // next hint: this is almost definitely not what you want.
  type **pda;  // probably better (need to use new/delete to make types)
};

ostream &operator<<(ostream &os, Register const &v) {
  for (int i = 0; i < v.elementNum; ++i) {
    // Calls proper virtual method for each instance.
    v.pData[i].dump(os); // XXX probably broken too
    v.pda[i]->dump(os); // should look more like this
    os << endl;
  }
}
于 2014-05-20T21:39:21.613 回答
0
type *pTemp = new type[elementNum+1];

这分配了一个类型为 的对象数组type。一个对象永远不能改变它的类型,你不能替换数组的元素,只能修改它。所以你的Register对象根本不包含任何派生类的对象,只包含那些具有基类类型的对象。

要以困难的方式获取异构对象数组,您需要一个指针数组:

type **pTemp = new (type*[elementNum+1]);

要以正确的方式做到这一点,您将避开数组和原始指针,而是使用容器和智能指针:

class Register {
public:
    const type& get(int pos) const;
    type& get(int pos);

    void Add(int pos, const type& obj);
    void Add(int pos, std::unique_ptr<type>&& ptr);

    // ...
private:
    std::vector<std::unique_ptr<type>> m_data;
};

但无论哪种方式,您从函数中放入了哪些指针Add

void Register::Add(int position,type& T);

可能不是&T传递的引用的地址。谁知道那个对象什么时候会被破坏。而且new type(T)也不好 - 它只是创建一个基本类型的对象,而忽略T. 因此,您可能需要一种clone()方法,有时称为“虚拟复制构造函数”:

class type {
public:
    using pointer = std::unique_ptr<type>;
    virtual ~type();
    virtual pointer clone() const;
};

type::pointer type::clone() const {
    return pointer(new type(*this));
}

type::pointer type2::clone() const {
    return pointer(new type2(*this));
}

上面我放了两个重载的Add(). 对象传递版本如下:

void Register::Add(int pos, const type& obj) {
    if (pos<0)
        return;
    if (pos >= m_data.size())
        m_data.resize(pos+1);
    m_data[pos] = obj.clone();
}

如果您碰巧已经拥有type::pointer一个对象,而不仅仅是一个对象,则另一个版本可能会很有用。有了这个重载,你可以把它移到 中Register,而不需要clone()任何东西。

void Register::Add(int pos, type::pointer&& ptr) {
    if (pos<0)
        return;
    if (pos >= m_data.size())
        m_data.resize(pos+1);
    m_data[pos] = std::move(ptr);
}
于 2014-05-20T23:03:51.283 回答