跳转至

练习:通过基类引用访问派生类对象


任务描述

设计 AnimalDog,将 Dog 对象绑定到 Animal&,验证派生类对象可隐式转换为基类引用。

相关知识

派生类对象可安全绑定到基类引用;该引用只能使用基类声明的接口。

向上转换与对象切片

Dog 绑定为 const Animal& 是向上转换,不会复制对象,也不会丢失派生类部分。不要把派生类对象按值传递给 Animal,否则会发生对象切片。本题要求 printAnimal 使用 const Animal& 参数。

基类接口设计

Animal 的名称成员应为私有成员;通过构造函数和 getName() 提供只读访问。测试代码只能经由 Animal 已声明的接口访问对象。

编程要求

  1. Animal 提供 getName() constDog : public Animal 通过构造函数设置名称。
  2. 完成 printAnimal(const Animal& animal),输出 动物:名称
  3. test 中将 Dog 传给该函数并断言输出。
  4. printAnimal 不得使用类型转换或访问 Dog 专有成员。
  5. Animal 的析构函数应声明为虚函数,为后续通过基类指针管理对象做好准备。

待完成代码

#include <cassert>
#include <iostream>
#include <sstream>
#include <string>

class Animal {
public:
    explicit Animal(const std::string& name);
    virtual ~Animal() = default;

    const std::string& getName() const;

private:
    std::string name_;
};

// TODO:完成 Animal 的成员函数定义。
Animal::Animal(const std::string& name)
    : name_(name) {
}

const std::string& Animal::getName() const {
    // TODO:返回名称成员。
}

class Dog : public Animal {
public:
    explicit Dog(const std::string& name);
};

// TODO:完成 Dog 的构造函数,使其将名称交给 Animal 初始化。
Dog::Dog(const std::string& name)
    : Animal(name) {
}

// TODO:只通过 Animal 的公开接口输出“动物:名称”。
void printAnimal(const Animal& animal) {
}

void test() {
    Dog dog("旺财");
    const Animal& animal = dog;
    assert(animal.getName() == "旺财");

    std::ostringstream output;
    std::streambuf* oldBuffer = std::cout.rdbuf(output.rdbuf());
    printAnimal(animal);
    std::cout.rdbuf(oldBuffer);
    assert(output.str() == "动物:旺财\n");
}

int main() {
    test();
    std::cout << "本关测试通过" << std::endl;
    return 0;
}

测试说明

第一项断言验证向上转换不改变对象状态;第二项断言验证普通函数只依赖基类接口。预期输出为 动物:旺财


开始你的任务吧,祝你成功!