1. 程式人生 > >C++ Primer筆記14_面向物件程式設計

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。而不會呼叫派生類的解構函式。