练习:通过基类引用访问派生类对象¶
任务描述¶
设计 Animal 与 Dog,将 Dog 对象绑定到 Animal&,验证派生类对象可隐式转换为基类引用。
相关知识¶
派生类对象可安全绑定到基类引用;该引用只能使用基类声明的接口。
向上转换与对象切片¶
将 Dog 绑定为 const Animal& 是向上转换,不会复制对象,也不会丢失派生类部分。不要把派生类对象按值传递给 Animal,否则会发生对象切片。本题要求 printAnimal 使用 const Animal& 参数。
基类接口设计¶
Animal 的名称成员应为私有成员;通过构造函数和 getName() 提供只读访问。测试代码只能经由 Animal 已声明的接口访问对象。
编程要求¶
Animal提供getName() const;Dog : public Animal通过构造函数设置名称。- 完成
printAnimal(const Animal& animal),输出动物:名称。 - 在
test中将Dog传给该函数并断言输出。 printAnimal不得使用类型转换或访问Dog专有成员。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;
}
测试说明¶
第一项断言验证向上转换不改变对象状态;第二项断言验证普通函数只依赖基类接口。预期输出为 动物:旺财。
开始你的任务吧,祝你成功!