C++入门(8):类的继承(1)
通过继承机制,可以对现有的、可信的代码进行扩展,并应用在新的程序中。
子类是从基类(父类或超类)派生出的类,形式为:
class SubClass:public(protected、private) SuperClass{...}
对象之间的关系:
1)继承:比如说“狗是一个宠物”,则可以创建一个名为 Pet(宠物)的基类,再由它派生出一个名为 Dog(狗)的子类 ,即“是一个”的关系;
2)组合: 另外一种情况,比如说“宠物有一个名字”,则可以创建一个名为 Pet(宠物)的基类,而 name(名字)应该是 Pet 类的一个组成部分,即“有一个” 的关系。
有些类与类之间存在一种组合关系,也叫聚集。
建立组合的做法是:创建一个新类,在它里面定义一个属性,而该属性是另一个类的对象;Python中也是这么做的。
对于继承,创建对象时,会先调用基类的构造器,再调用子类的构造器。因为基类必须在子类之前初始化;
与构造器情况相反,基类的析构器将在子类的最后一条语句执行完毕之后才被调用,即调用基类的析构器是最后一件事情。
这节我们主要讨论继承,下面通过举例来了解类的继承:
#include <iostream>
#include <string>
class Pet{ //基类
public:
std::string name; //属性
Pet(std::string name = "pet") ; //构造函数
~Pet() ; //析构函数
void eat(); //方法
void sleep();
void setName(std::string name);
};
class Dog : public Pet{ //Dog子类
public:
Dog();
~Dog();
void bark(); //子类Dog中的方法
};
class Cat : public Pet{ //Cat子类
public:
Cat(std::string name) ;
~Cat();
void climb(); //子类Cat中的方法
};
//方法的实现
Pet::Pet(std::string name) //定义构造器的时候,如果有默认参数,不用写出其初始化值 !!
std::cout << "I am Pet's Constructor." << std::endl;
this->name = name;
}
Pet::~Pet()
{
std::cout << "I am Pet's Destructor." << std::endl;
}
void Pet::eat()
{
std::cout << "This " << name << " is eating... " << std::endl;
}
void Pet::sleep()
{
std::cout << "This " << name << " is sleeping..." << std::endl;
}
void Pet::setName(std::string name)
{
this->name = name;
}
Dog::Dog()
{
std::cout << "I am Dog's Constructor." << std::endl;
}
Dog::~Dog()
{
std::cout << "I am Dog's Destructor." << std::endl;
}
void Dog::bark()
{
std::cout << "This " << name << " is barking..." << std::endl;
}
Cat::Cat(std::string name):Pet(name) //子类构造器继承基类的构造器
{
this->name = name; //这句赋值语句不需要,实际的初始化在基类中完成
std::cout << "I am Cat's Constructor." << std::endl;
Cat::~Cat()
{
std::cout << "I am Cat's Destructor." << std::endl;
}
void Cat::climb()
{
std::cout << "This " << name << " is climbing..." << std::endl;
}
int main(int argc, char** argv) {
Pet pet;
Dog dog; //先调用一次Pet的构造器,再调用一次Dog的构造器
Cat cat("cat"); //先调用一次Pet的构造器,再调用一次Cat的构造器
dog.eat(); //dog没有初始化,所以使用的是基类Pet的默认参数
dog.setName("dog"); //Dog类构造器没有初始化方法,调用基类的setName方法同样可以初始化name属性
dog.sleep();
dog.bark();
cat.climb(); //定义Cat的时候已经调用了构造函数初始化了
pet.sleep() ;
//程序结束时,依次调用类的析构器
return 0;
}
运行结果为:
I am Pet's Constructor.
I am Pet's Constructor.
I am Dog's Constructor.
I am Pet's Constructor.
I am Cat's Destructor.
This pet is eating...
This dog is sleeping...
This dog is barking...
This cat is climbing...
This pet is sleeping...
I am Cat's Constructor.
I am Pet's Constructor.
I am Dog's Constructor.
I am Pet's Constructor.
I am Pet's Constructor.