C++ 如何从 array/collection 基本元素调用子运算符 <<(ostream)

C++ how to invoke a child's operator<<(ostream) from an array/collection of base elements

假设我有一个人 class 有一个字段 字符串名称 。现在让我们有一个 class 学生派生具有字段 int avgGrade 的 Person。两个 classes 都定义了运算符<<。

我希望能够将 Person 类型的元素存储在数组或类似结构中,而且还能够在其中存储派生的 class 对象。稍后我将遍历元素并希望使用运算符 << 并实际为该运算符调用该特定对象的定义,而不是始终调用它的基本版本。

我该怎么做?我应该在什么结构中存储什么类型的元素?

这是 classes 的当前集合:

Person.h:

#pragma once
#include <iostream>
class Person
{
private:
    std::string name;
public:
    Person();
    Person(std::string);

    friend std::ostream& operator<<(std::ostream& os, const Person& obj);
}

Person.cpp:

#include "Person.h"

Person::Person() : Person("default") { }


Person::Person(std::string name)
{
    this->name = name;
}

std::ostream& operator<<(std::ostream& os, const Person& obj)
{
    os << "Name: " << obj.name;
    return os;
}

Student.h:

#pragma once
#include "Person.h"
#include <iostream>

class Student : Person
{
private:
    double avgGrade;
public:
    Student();
    Student(const std::string cs, const double avg_grade);

    friend std::ostream& operator<<(std::ostream& os, const Student& obj);
};

Student.cpp:

#include "Student.h"

Student::Student() : Student("default", 4) { }


Student::Student(const std::string cs, const double avg_grade)
    : Person(cs),
    avgGrade(avg_grade)
{
    this->avgGrade = avg_grade;
}

std::ostream& operator<<(std::ostream& os, const Student& obj)
{
    os << (Person)obj << std::endl;
    os << "Average grade: " << obj.avgGrade;
    return os;
}

Demo.cpp:

#include "Person.h"
#include "Student.h"
#include <iostream>

int main(int argc, char* argv[])
{
    Person p("john");
    Student s("johana", 5);


    Person* arr[2];
    arr[0] = &p;
    arr[1] = &s; // Error: conversion to inaccessible base class "Person" is not allowed

    std::cout << arr[0] << std::endl;
    std::cout << arr[1] << std::endl;


    return 0;
}

解决这类问题的一般方法是声明:

inline std::ostream& operator<<(std::ostream& str, const Base& o)
{
    o.print(str);
    return str;
}

作为非成员函数,则:

    virtual void print(std::ostream& str);

Base 中,并根据需要在 Derived 中覆盖。 (Derived 版本可能以 Base::print(str); 开头来调用基础版本。)

您对 array 的声明很好,但您随后会使用以下内容打印元素:

    std::cout << *arr[0] << std::endl;
    std::cout << *arr[1] << std::endl;

初始化数组的问题是,默认情况下,基 类 是私有的。解决这个问题:

class Student : public Person ...