当我们创建 Derived 对象时,它包含 Base 的部分(首先构建)以及属于 Derived 的部分 (随后构建)。注意,继承关系隐含的是对象A“是一种”对象B的含义。因为 Derived 是一个 Base,所以 Derived 包含 Base 的部分是合理的。
指针,引用和派生类
创建一个指向 Derived 对象的指针和引用很简单:
1 2 3 4 5 6 7 8 9101112131415
#include<iostream>intmain(){Derivedderived{5};std::cout<<"derived is a "<<derived.getName()<<" and has value "<<derived.getValue()<<'\n';Derived&rDerived{derived};std::cout<<"rDerived is a "<<rDerived.getName()<<" and has value "<<rDerived.getValue()<<'\n';Derived*pDerived{&derived};std::cout<<"pDerived is a "<<pDerived->getName()<<" and has value "<<pDerived->getValue()<<'\n';return0;}
输出结果如下:
123
derived is a Derived and has value 5
rDerived is a Derived and has value 5
pDerived is a Derived and has value 5
不过,由于 Derived 中包含属于 Base 的部分,那么我们不禁要问:C++允许我们将Base类型指针指向Derived 对象吗?答案是可以的!
1 2 3 4 5 6 7 8 910111213141516
#include<iostream>intmain(){Derivedderived{5};// These are both legal!Base&rBase{derived};Base*pBase{&derived};std::cout<<"derived is a "<<derived.getName()<<" and has value "<<derived.getValue()<<'\n';std::cout<<"rBase is a "<<rBase.getName()<<" and has value "<<rBase.getValue()<<'\n';std::cout<<"pBase is a "<<pBase->getName()<<" and has value "<<pBase->getValue()<<'\n';return0;}
程序运行结果如下:
123
derived is a Derived and has value 5
rBase is a Base and has value 5
pBase is a Base and has value 5
#include<iostream>#include<string_view>#include<string>classAnimal{protected:std::stringm_name;// 将这个构造函数设置为受保护的,因为// 我们不希望用户能够直接创建 Animal 对象,// 但是我们仍然希望能够使用它来派生类。Animal(std::string_viewname):m_name{name}{}// To prevent slicing (covered later)Animal(constAnimal&)=default;Animal&operator=(constAnimal&)=default;public:std::string_viewgetName()const{returnm_name;}std::string_viewspeak()const{return"???";}};classCat:publicAnimal{public:Cat(std::string_viewname):Animal{name}{}std::string_viewspeak()const{return"Meow";}};classDog:publicAnimal{public:Dog(std::string_viewname):Animal{name}{}std::string_viewspeak()const{return"Woof";}};intmain(){constCatcat{"Fred"};std::cout<<"cat is named "<<cat.getName()<<", and it says "<<cat.speak()<<'\n';constDogdog{"Garbo"};std::cout<<"dog is named "<<dog.getName()<<", and it says "<<dog.speak()<<'\n';constAnimal*pAnimal{&cat};std::cout<<"pAnimal is named "<<pAnimal->getName()<<", and it says "<<pAnimal->speak()<<'\n';pAnimal=&dog;std::cout<<"pAnimal is named "<<pAnimal->getName()<<", and it says "<<pAnimal->speak()<<'\n';return0;}
打印结果
1234
cat is named Fred, and it says Meow
dog is named Garbo, and it says Woof
pAnimal is named Fred, and it says ???
pAnimal is named Garbo, and it says ???
#include<array>#include<iostream>// Cat and Dog from the example aboveintmain(){constCatfred{"Fred"};constCatmisty{"Misty"};constCatzeke{"Zeke"};constDoggarbo{"Garbo"};constDogpooky{"Pooky"};constDogtruffle{"Truffle"};// Set up an array of pointers to animals, and set those pointers to our Cat and Dog objects// Note: to_array requires C++20 support (and at the time of writing, Visual Studio 2022 still doesn't support it correctly)constautoanimals{std::to_array<constAnimal*>({&fred,&garbo,&misty,&pooky,&truffle,&zeke})};// Before C++20, with the array size being explicitly specified// const std::array<const Animal*, 6> animals{ &fred, &garbo, &misty, &pooky, &truffle, &zeke };for(constautoanimal:animals){std::cout<<animal->getName()<<" says "<<animal->speak()<<'\n';}return0;}