指向基址的指针列表 class-理解代码

list of pointer to base class-understand code

我正在接受 C++ 考试培训,但我不明白为什么代码只显示基本 class 的打印功能(也是在我调试代码之后),而从不打印派生的class。 你能用简单的方式向我解释为什么吗?为了仅通过编辑几行代码也能显示派生 class 的打印功能,我能做些什么吗? 假设程序生成的数字是:1 67 0 69 0 0 58 78.

class A
{
    int a;
public:
    A(int x):a(x){}

    void print() { cout << "a=" << a << ' '; }
};

class B:public A
{
    int b;
public:
    B(int x,int y) :A(x),b(y) {}
    void print() { A::print(); cout << "b=" << b << ' '; }
};

int main(){
    list<A*> lst;
    for (int i = 0; i < 3; i++)
        if(rand()%2)
            lst.push_back(new A(rand() % 100));
        else
            lst.push_back(new B(rand() % 100,rand()%100));
    for (list<A*>::iterator it = lst.begin(); it != lst.end(); it++)
        (*it)->print();
}

您需要声明 print() 虚拟才能使多态性起作用。

这是您的示例,其中包含建议的格式改进,

#include <iostream>
#include <list>

class A{
    int a;
public:
    A(int x):a(x){}
    virtual void print() { std::cout << "a=" << a << ' '; }
};

class B:public A{
    int b;
public:
    B(int x,int y) :A(x),b(y) {}
    void print() override { A::print(); std::cout << "b=" << b << ' '; }
};

int main(){
    std::list<A*> lst;
    for (int i = 0; i < 30; i++) {
        if(rand()%2) {
            lst.push_back(new A(rand() % 100));
        } else {
            lst.push_back(new B(rand() % 100,rand()%100));
        }
    }
    for (std::list<A*>::iterator it = lst.begin(); it != lst.end(); it++) {
        (*it)->print();
    }
}

我增加了打印元素的数量,因为在这些设置中我没有得到一个 b。这表示:

  • 如果您不想一遍又一遍地获得相同的数字,则需要使用 srand 为您的代码播种(并且每个程序只需要播种一次)。
  • 如果可能,您应该使用从 C++11 开始可用的 new random number 生成功能。
  • override 是可选的,但非常鼓励,它清楚地表明该功能是虚拟的并重新实现。
  • 最重要的是,您需要释放使用 new 分配的内存(使用 delete),或者更好的是,使用@TedLyngmo 答案中的方法(智能指针)

为了使用动态调度,你需要A::print() virtual。您还需要使 A 的析构函数 virtual 能够通过基 class 指针 delete 对象。

由于您目前没有 delete 任何对象(而是泄漏所有 AB)我建议您使用智能指针,std::unique_ptr<A>,将在 std::list 被销毁时清理。

示例:

#include <iostream>
#include <list>
#include <memory>   // std::unique_ptr

class A {
    int a;

public:
    A(int x) : a(x) {}
    virtual ~A() = default;  // virtual destructor

    virtual void print() { std::cout << "a=" << a << ' '; }
};

class B : public A {
    int b;

public:
    B(int x, int y) : A(x), b(y) {}
    void print() override {
        A::print();
        std::cout << "b=" << b << ' ';
    }
};

int main() {
    std::list<std::unique_ptr<A>> lst;   // use of smart pointer

    for(int i = 0; i < 30; i++) {
        if(rand() % 2) {
            lst.emplace_back(std::make_unique<A>(rand() % 100));
        } else {
            lst.emplace_back(std::make_unique<B>(rand() % 100, rand() % 100));
        }
    }
    for(auto it = lst.begin(); it != lst.end(); it++) {
        (*it)->print();
    }

    // Simpler loop: A range-based for loop:
    // for(auto& ptr : lst) ptr->print();
}