打印出存储在具有相同祖先的不同类的变量中的值

Print out the values stored in vars of different classes, that have the same ancestor

本文关键字:同类 变量 祖先 存储 打印      更新时间:2023-10-16

我有这个类:

class CComputer {
public:
    // constructor    
    CComputer(string name) {
        this->name = name;
    };
    // overloaded operator << for printing
    friend ostream& operator<<(ostream& os, const CComputer& c);
    // adds some component for this computer
    CComputer & AddComponent(Component const & component) {
        this->listOfComponents.push_back(component);
        return *this;
    };
    // sets address for this computer
    CComputer & AddAddress(const string & address) {
        this->address = address;
        return *this;
    };
    string name;
    string address;
    list<Component> listOfComponents;
};

然后是这些类:

// ancestor for other classes...It's really dummy yet, but I dunno what to add there
class Component {
public:
    Component() {};
    ~Component() {};
};
class CCPU : public Component {
public:
    CCPU(int cores, int freq) {
        this->cores = cores;
        this->freq = freq;
    };
    int cores;
    int freq;
};
class CMemory : public Component {
public:
    CMemory(int mem) {
        this->mem = mem;
    };
    int mem;
};

现在我给我的CComputer类提供一些值:

 CComputer c("test.com");
 c . AddAddress("123.45.678.910") .
     AddComponent(CCPU(8, 2400)) .
     AddComponent(CCPU(8, 1200)).
     AddComponent(CMemory(2000)).
     AddComponent(CMemory(2000)));

现在我想把我放在那里的所有信息打印出来(包括CCPUCMemory的详细信息(

但是如何实现它,能够在CComputer::listOfComponents中迭代,而不在乎我是实际访问CCPU还是CMemory?我可以将它添加到该列表中,但我真的不知道如何创建它,以便能够访问这些组件的变量。

所以输出应该看起来像:

##### STARTING #####
CComputer:
   name:test.com
   address:123.45.678.910
      CCPU:
         cores:8,freq:2400
      CCPU:
         cores:8, freq:1200
      CMemory:
         mem:2000
      CMemory:
         mem:2000
###### FINISHED! #####

正如其他人所提到的,您需要在基类中实现一个由每个子类继承和重写的虚拟函数(例如virtual std::string ToString() const = 0;(。

然而,这还不够。您的代码展示了当您将子类实例复制到列表中时发生的切片:列表包含类型为Component的对象,而不是相关子类的对象。

您需要做的是存储多态实例。值本身从来都不是多态的,您需要为此使用(智能(指针或引用。但是,引用是不存在的,因为不能将它们存储在标准容器(如std::list(中。现在,使用原始指针被认为是一种糟糕的风格,但从类的命名约定来看,你在类中没有学习到现代C++(对不起!(。

因此,原始指针可能是最好的选择。相应地更改您的代码:

  • 存储指针列表:

    list<Component*> listOfComponents;
    
  • AddComponent的参数类型设置为指针,而不是const&

  • 通过传递new ed对象来调用函数,例如:

    AddComponent(new CCPU(8, 2400))
    

现在,您的代码向左、向右和居中泄漏内存。你需要实现一个析构函数来释放内存:

~CComputer() {
    typedef std::list<Component*>::iterator iter_t;
    for (iter_t i = listOfComponents.begin(); i != listOfComponents.end(); ++i)
        delete *i;
}

但是现在你的代码违反了三条规则(阅读这篇文章!这很重要,这可能是你将在这个编程类中学习的C++最有用的东西(,因此你还需要实现复制构造函数和复制赋值运算符。然而,我们不能。很抱歉为了实现类的复制,您必须在Component类中实现另一个虚拟函数,即克隆对象(virtual Component* Clone() const = 0;(的函数。只有然后才能继续。

以下是CCPU中的示例实现:

Component* Clone() const {
    return new CCPU(cores, freq);
}

…这需要在从Component派生的所有类中完成,否则我们无法正确复制从Component派生并隐藏在指针后面的类型的对象。

现在我们可以在CComputer类中实现复制:

CComputer(CComputer const& other)
        : name(name)
        , address(addess) {
    typedef std::list<Component*>::iterator iter_t;
    for (iter_t i = other.listOfComponents.begin(); i != other.listOfComponents.end(); ++i)
        listOfComponents.push_back((*i)->Clone());
}
CComputer& operator =(CComputer const& other) {
    if (this == &other)
        return *this;
    name = other.name;
    address = other.address;
    listOfComponents.clear();
    for (iter_t i = other.listOfComponents.begin(); i != other.listOfComponents.end(); ++i)
        listOfComponents.push_back((*i)->Clone());
    return *this;
}

这段代码很脆弱,不是线程安全的,而且很容易出错,没有一个称职的C++程序员会写这1Real代码会使用智能指针,但正如前面提到的,我确信这超出了类的范围。


1我想知道这让我现在怎么样了?

只需向class Component添加一个名为toString((的虚拟方法,该方法将返回一个描述组件的字符串。然后你可以遍历所有组件并调用toString((,而不用担心每个组件到底是什么。如果你这样做,那么对于每台计算机,你就可以打印出所有组件的值。

然而,正如其中一条评论中所指出的,您在问题中给出的示例输出输出了所有计算机的CCPU,然后是所有计算机的所有内存。要对输出进行这样的排序,您需要向Component添加另一个名为getType((的虚拟方法,该方法返回表示信息类型的枚举或整数。然后,您可以有两个for next循环,一个嵌套在另一个循环中,其中外部循环遍历所有类型,内部循环遍历所有计算机,调用与外部for循环中指定的类型匹配的所有组件上的toString((。

以下是实现这个想法的东西。

#include <iostream>
#include <string>
#include <list>
using namespace std;
int const TYPE_CCPU = 1;
int const TYPE_MEMORY = 2;
class Component {
public:
    virtual int GetType() { return -1; }
    virtual std::string ToString() const {
        return "OOPS! Default `ToString` called";
    }
};
class CComputer {
public:
    typedef std::list<Component*>::iterator iter_t;
    // constructor    
    CComputer(string name) {
        this->name = name;
    };
    ~CComputer() {
        for (iter_t i = listOfComponents.begin(); i != listOfComponents.end(); ++i) {
            delete *i;
        }
    }
    // overloaded operator << for printing
    friend ostream& operator<<(ostream& os, const CComputer& c);
    // adds some component for this computer
    CComputer & AddComponent(Component *component) {
        this->listOfComponents.push_back(component);
        return *this;
    };
    // sets address for this computer
    CComputer & AddAddress(const string & address) {
        this->address = address;
        return *this;
    };
    void PrintType(int type) {
        for (iter_t i = listOfComponents.begin(); i != listOfComponents.end(); ++i) {
            if ((*i)->GetType() == type)
                std::cout << (*i)->ToString() << 'n';
        }
    }
    string name;
    string address;
    list<Component*> listOfComponents;
};
class CCPU : public Component {
public:
    CCPU(int cores, int freq) {
        this->cores = cores;
        this->freq = freq;
    };
    int GetType() { return TYPE_CCPU; }
    std::string ToString() const {
        return "CCPU::ToString()";
    }
    int cores;
    int freq;
};
class CMemory : public Component {
public:
    CMemory(int mem) { this->mem = mem; };
    int GetType() { return TYPE_MEMORY; }
    std::string ToString() const {
        return "CMemory::ToString()";
    }
    int mem;
};
typedef std::list<CComputer*>::iterator iter_c;
int main() {
    list<CComputer*> computerlist;
    CComputer *c1 = new CComputer("test.com"), *c2 = new CComputer("test2.com");
    c1->AddAddress("123.45.678.910").
        AddComponent(new CCPU(8, 1200)).
        AddComponent(new CMemory(2000));
    computerlist.push_back(c1);
    c2->AddAddress("987.65.432.10").
        AddComponent(new CCPU(8, 2400)).
        AddComponent(new CMemory(4000));
    computerlist.push_back(c2);
    for(int t=TYPE_CCPU; t<=TYPE_MEMORY; t++) 
        for (iter_c i = computerlist.begin(); i != computerlist.end(); ++i) {
            (*i)->PrintType(t);
    }
    for (iter_c i = computerlist.begin(); i != computerlist.end(); ++i) {
        delete (*i);
    }
}

在每个类中实现ToString((。在.NET中,这是一个标准,即使是"对象"类型也能实现。