C++ Primer筆記14_面向物件程式設計
OOP概述
面向物件程式設計(object-oriented programming)的核心思想是資料抽象、繼承和動態繫結。
1.繼承:
類的一種層次關係,通常在層次關係的根部有一個基類,其它類則直接或間接的繼承基類而來。這些繼承而來的類稱為派生類。
基類希望它的派生類自己定義適合自身的版本號的函式。基類就將函式宣告為虛擬函式,加上virtualkeyword。
2.動態繫結:
通過動態繫結,能夠使用同一段程式碼處理基類和子類物件。
在C++中。當我們使用基類的引用或指標呼叫一個虛擬函式時會發生動態繫結。有虛擬函式(virtual)才會發生動態繫結
在C++中,基類必須將它的兩種成員函式區分開,一種是希望派生類進行覆蓋的函式。一種是希望派生類直接繼承而不覆蓋的函式。
當且僅當通過指標或引用對虛擬函式呼叫時會在執行時被解析。
3.派生類建構函式:
派生類中含有從基類繼承而來的成員。派生類必須使用基類的建構函式來初始化它的基類部分。
派生類能夠訪問基類的公有(public)成員和受保護(protected)成員。
4.純虛擬函式:
在函式體宣告最後寫=0,就可以將一個函式宣告為純虛擬函式。
含有純虛擬函式的類是抽象基類。抽象基類僅僅負責定義介面,興許的其它類能夠覆蓋該介面。
不能直接建立一個抽象基類的物件(含有純虛擬函式的類不能直接例項化)。
派生類假設未定義繼承而來的純虛擬函式,則派生類也是抽象類。不能例項化。
5.類的作用域:
每一個類有自己的作用域,在這個作用域內我們定義類的成員。
當存在繼承關係時,派生類作用域巢狀在基類作用域內,假設一個名字在派生類的作用域內無法解析,則編譯器將繼續在外層的基類中尋找該名字的定義。
派生類的成員將隱藏同名的基類成員。
6.隱藏、覆蓋。過載的差別:
(覆蓋即派生類自己實現了基類中同名的函式(虛擬函式), 函式覆蓋發生在父類與子類之間。其函式名、引數型別、返回值型別必須同父類中的相相應被覆蓋的函式嚴格一致
僅僅要基類在定義成員函式時已經聲明瞭virtualkeyword,在派生類實現的時候覆蓋該函式時。virtualkeyword可加可不加,不影響多型的實現。
easy與隱藏混淆:
隱藏是指派生類的函式遮蔽了與其同名的基類函式。規則例如以下:
1) 假設派生類的函式與基類的函式同名。可是引數不同。此時,不論有無virtualkeyword,基類的函式將被隱藏(注意別與過載混淆)。
2) 假設派生類的函式與基類的函式同名,而且引數也同樣。可是基類函式沒有virtualkeyword。此時。基類的函式被隱藏(注意別與覆蓋混淆)。
比方,在以下的程式中:
#include <iostream.h>
class Base
{
public:
virtual void f(float x){ cout << "Base::f(float) " << x << endl; }
void g(float x){ cout << "Base::g(float) " << x << endl; }
void h(float x){ cout << "Base::h(float) " << x << endl; }
};
class Derived : public Base
{
public:
virtual void f(float x){ cout << "Derived::f(float) " << x << endl; }
void g(int x){ cout << "Derived::g(int) " << x << endl; }
void h(float x){ cout << "Derived::h(float) " << x << endl; }
};
通過分析可得: 1) 函式Derived::f(float)覆蓋了Base::f(float)。
2) 函式Derived::g(int)隱藏了Base::g(float),注意。不是過載。
3) 函式Derived::h(float)隱藏了Base::h(float),而不是覆蓋。
7.樣例
test.h
#ifndef _TEST_H
#define _TEST_H
using namespace std;
#include <string>
class Animal
{
public:
Animal();
Animal(int a);
virtual ~Animal();
virtual void shout();
virtual void fight() = 0;
void eat();
void sleep();
protected:
int age;
};
class Person : public Animal
{
public:
Person();
Person(int a, string n);
~Person();
virtual void shout();//Cover!
//virtual void shout()const;//Hide!
virtual void fight();//Cover
void eat(string &n);//Hide not override!
void sleep();//Hide not Cover!
void show();
private:
//int age;//Hide!
string name;
};
#endif
test.cpp
#include <iostream>
#include "test.h"
Animal::Animal():age(0)
{
cout << "Animal 1" << endl;
}
Animal::Animal(int a):age(a)
{
cout << "Animal 2" << endl;
}
Animal::~Animal()
{
cout << "~ Animal " << endl;
}
void Animal::shout()
{
cout << "Animal Shout!" << endl;
}
void Animal::eat()
{
cout << "Animal eat!" << endl;
}
void Animal::sleep()
{
cout << "Animal sleep!" << endl;
}
//----------------------------------------------------------------
Person::Person()
{
cout << "Person 1" << endl;
}
Person::Person(int a, string n):Animal(a), name(n)//call Base class Counstruction Fun
{
cout << "Person 2" << endl;
}
Person::~Person()
{
cout << "~ Person " << endl;
}
void Person::shout()
{
cout << "Person Shout!" << endl;
}
void Person::fight()
{
cout << "Person fight!" << endl;
}
/*
void Person::shout()const
{
cout << "const Person Shout!" << endl;
}
*/
void Person::show()
{
cout << "I'm Person, Age: " << age << " Name: " << name << endl;
}
void Person::eat(string &n)
{
cout << "Person: " << name << " eat!" << endl;
}
void Person::sleep()
{
cout << "Person sleep!" << endl;
}
main.cpp
#include <iostream>
#include "test.h"
int main()
{
Animal *p = new Person(20, "July");
p->shout();//run time bind!
p->fight();
p->eat();
p->sleep();
delete p;//~ Animal
//when add virtual before ~Animal() will output : ~ Person ~ Animal
//Animal *p = new Animal(20, "July"); the class has pure virtual functions cannot init!
//if shout() is declared as : void shout(); p->shout() output :Animal shout not run time bind!
/*
Person p(20, "Mike");
Animal &refP = p;
refP.shout();
*/
// p->show(); Error Animal has no number of show
return 0;
}
執行結果:
Animal 2
Person 2
Person Shout!
Person fight!
Animal eat!
Animal sleep!
~ Person
~ Animal
能夠得出這樣一個結論,被隱藏的函式是不能實現多型的。僅僅有覆蓋virtual函式才幹。
另外。基類解構函式須要加virtual。以便於正確的呼叫基類與派生類的解構函式。假設不加,delete p僅僅會輸出:
~Animal。而不會呼叫派生類的解構函式。