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.