《Essential C++》笔记之漫游:面向对象编程思维

《Essential C++》笔记之漫游:面向对象编程思维_第1张图片

面向对象编程概念:

  面向对象编程概念的两项最主要特质是∶继承(inheritance)多态(polymorphism)前者使我们得以将一群相关的类组织起来,并让我们得以分享其间的共通数据和操作行为,后者让我们在这些类之上进行编程时,可以如同操控单一个体,而非相互独立的类,并赋予我们更多弹性来加入或移除任何特定类。

继承机制:

  继承机制定义了父子(parent/chid)关系。父类(parent)定义了所有子类(children)共通的公有接口(public interface)和私有实现(private implementation)。每个子类都可以增加或覆盖(override)继承而来的东西,以实现其自身独特的行为。例如,子类AudioBook(有声书)除了从父类Book继承了作者和标题之外,还增加了播讲者以及耗用的卡带数。除此之外,它也改写了从父类继承而来的check_out()函数。
  在C++中,父类被称为基类(base class)子类被称为派生类(derived class)。父类和子类之间的关系则称为继承体系(inheritance hierarchy)例如在整个设计的复审会议中,我们可能会说:“我希望实现一个AudioBook派生类。它会覆盖基类Book的check_out()操作方法。不过,它还是沿用继承而来的 Book类中的各笔数据,以及用来管理架位、作者、标题等信息的操作函数。”
  下图绘出了图书馆借阅管理系统中用到的各种馆藏的类体系。这一继承体系中最根本的类乃是一个抽象基类(abstract base class):LibMat。LibMat用来定义图书馆借阅管理系统中所有馆藏的共通操作行为,包括∶check_in()、check_out()、due_date()、find()、location(),等等。LibMat并不代表图书馆借阅管理系统中实际存在的任何一个馆藏,仅仅是为了我们设计上的需要而存在。但事实上这个抽象十分关键。我们称之为"抽象基类(abstract base class)"
《Essential C++》笔记之漫游:面向对象编程思维_第2张图片
  在面向对象应用程序中,我们会间接利用“指向抽象基类”的pointer或reference来操作系统中的对象,而不是直接操作各个实际对象。这让我们得以在不更动旧有程序的前提下,加入或移除任何一个派生类。
《Essential C++》笔记之漫游:面向对象编程思维_第3张图片

多态:

  面向对象编程风格的第二个独特概念是多态(polymorphism)∶让基类的pointer或reference得以十分透明地(transparently)指向其任何一个派生类的对象。以上述的loan_check_in()为例,mat总是指向(代表)LibMat的某个派生对象。但究竟是哪一个?答案是除非程序实际执行的当下,否则无法确定。而且,loan_check_in ()的每次执行情况都可能不同。

动态绑定:

  动态绑定(dynamic binding)是面向对象编程风格的第三个独特概念。在非面向对象的编程风格中,当我们写下这样—行∶

  mat.check_in();

  编译器在编译时就依据 mat 所属的类决定究竟执行哪一个 check_in()函数。由于程序执行之前就已解析出应该调用哪一个函数,所以这种方式被称为静态绑定(static binding)
  但在面向对象编程方法中,编译器无法得知究竟哪一份 check_in()函数会被调用。每次loan_check_in()执行时,仅能在执行过程中依据mat所指的实际对象来决定调用哪一个check_in()。"找出实际被调用的究竟是哪一个派生类的check_in()函数"这一解析操作会延迟至运行时(run-time)才进行。此即我们所谓的动态绑定(dynamic binding)。

总之:

  继承特性让我们得以定义一整群互有关联的类,并共享共通的接口,就像前述的各种图书馆藏。

  多态则让我们得以用一种与类型无关(type-independent)的方式来操作这些类对象。我们通过抽象基类的pointer或reference来操控其共通接口。

  而实际执行起来的操作则需要等到运行时,依据pointer或 reference 所指的实际对象的类型才能决定。是的!多态和动态绑定的特性,只有在使用 pointer 或reference时才能发挥。稍后我会多加说明。

——《Essential C++》中文版 Page 135

漫游:面向对象编程思维

  实现一个三层的类体系,并借此引入C++语言中的基本组成和支持面向对象编程的语法元素。我以LibMat这个抽象基类作为类体系中的最根本的类。从LibMat派生出Book,并从Book派生出AudioBook。限定接口只有一个constructor、一个destructor和一个print()函数。为每个member function加上一些程序代码,输出信息表示它们的存在,让我们得以跟踪程序的行为。
  默认情形下,member function的解析皆在编译时静态地进行。若要令其在运行时动态进行,我们就得在它的声明前加上关键字virtual。LibMat的声明表示,其destructor和print()皆为virtual(虚函数)。关于虚函数更为细致的解读可参考博文C++ 子类继承父类纯虚函数、虚函数和普通函数的区别和博文C++之关于虚函数和多态的分析和补充

例1第一次调用分析:

  我在main()程序中重复调用print(),并依次将LibMat对象、Book对象、AudioBook对象当作参数传递给它。每次print()被执行,都会依据mat实际所指的对象,在LibMat、Book、AudioBook三者之间挑选正确的print() member function加以调用。第一次调用操作像下面这样:

《Essential C++》笔记之漫游:面向对象编程思维_第4张图片

  Default constructor的调用乃是紧跟在libmat的定义行为之后。而在print()中,mat.print()会被解析为LibMat::print()。接踵而来的便是LibMat destructor的调用

例1第二次调用分析:

  将Book对象传入print():
  我们该如何实现派生类 Book 呢?为了清楚标示这个新类乃是继承自一个已存在的类,其名称之后必须接一个冒号:,然后紧跟着关键字public和基类的名称。


  第一个印象是,通过mat.print()所进行的虚拟调用(virtual invocation)操作的确有效!被调用的函数是Book::print()而非LibMat::print()。第二件令人感兴趣的事是,当程序定义出一个派生对象,基类和派生类的constructor都会被执行。(当派生对象被销毁,基类和派生类的destructor也都会被执行〔但次序颠倒〕。)
  Book中的print()覆盖(override)了LibMat的print()。这也正是mat.print()所调用的函数。title()和author()是两个所谓的访问函数(access function),都是non-virtual inline函数。过去我们不曾介绍关键字protected,是的,被声明为protected的所有成员都可以被派生类直接访问,除此(派生类)之外,都不得直接访问protected成员。

例1第三次调用分析:

  接下来,我从Book类派生出一个更特殊的AudioBook类。AudioBook除了拥有标题和作者,还有播讲者。在查看其实现之前,先让我把AudioBook对象传给print()∶
  该如何实现AudioBook这个派生类呢?我们只需要把焦点放在AudioBook与其基类Book的不同之处——也就是 print()——即可。当然,我们还必须提供 AudioBook 播讲者姓名,以及这个类的constructor和 destructor。至于Book类所提供的各项数据及操作函数,均可被AudioBook直接使用,仿佛它们本来便是由AudioBook定义似的。
  使用派生类时不必刻意区分"继承而来的成员"和“自身定义的成员”。两者的使用完全透明。

例1代码:

//小问学编程
#include 
#include 
#include 
using namespace std;

class LibMat {
public:
	LibMat(){
		cout << "LibMat::LibMat() default constructor!\n";
	}

	virtual ~LibMat(){
		cout << "LibMat::~LibMat() destructor!\n";
	}

	virtual void print() const {
		cout << "LibMat::print() -- I am a LibMat object!\n";
	}
};

class Book : public LibMat {
public:
	Book( const string &title, const string &author )
		: _title( title ), _author( author ){
		cout << "Book::Book( " << _title
			 << ", " << _author << " )  constructor\n";
	}

	~Book(){
		cout << "Book::~Book() destructor!\n";
	}

	virtual void print() const {
		cout << "Book::print() -- I am a Book object!\n"
			 << "My title is: " << _title << '\n'
			 << "My author is: " << _author << endl;
	}

	const string& title() const { return _title; }
	const string& author() const { return _author; }

protected:
	string _title;
	string _author;
};

class AudioBook : public Book {
public:
	AudioBook( const string &title,
		       const string &author, const string &narrator )
		: Book( title, author ), _narrator( narrator ){
		cout << "AudioBook::AudioBook( " << _title
			 << ", " << _author
			 << ", " << _narrator
			 << " )  constructor\n";
	}

	~AudioBook(){
		cout << "AudioBook::~AudioBook() destructor!\n";
	}

	virtual void print() const {
		cout << "AudioBook::print() -- I am a AudioBook object!\n"
			 << "My title is: " << _title << '\n'
			 << "My author is: " << _author << '\n'
			 << "My narrator is: " << _narrator << endl;
	}

	const string& narrator() const { return _narrator; }

protected:
	string _narrator;
};

void print( const LibMat &mat )
{
	cout << "in global print(): about to print mat.print()\n";
	mat.print();
}

int main()
{

	// objects are in local blocks to force destruction
	{
        cout << "\n" << "Creating a LibMat object to print()\n";
  	    LibMat m;
	    print(m);
	}

	{
        cout << "\n" << "Creating a Book object to print()\n";
	    Book b( "The Castle", "Franz Kafka" );
	    print(b);
	}

	{
        cout << "\n" << "Creating a AudioBook object to print()\n";
	    AudioBook ab( "Man Without Qualities", "Robert Musil", "Kenneth Meyer" );
	    print(ab);
	}

	return 0; // unnecessary but quiets vc++
}
//本代码改自《Essential C++》中文版P138-P142

运行结果:
《Essential C++》笔记之漫游:面向对象编程思维_第5张图片

例2( 例1代码中去掉了void print( const LibMat &mat )

//小问学编程
#include 
#include 
#include 
using namespace std;

class LibMat {
public:
	LibMat(){
		cout << "LibMat::LibMat() default constructor!\n";
	}

	virtual ~LibMat(){
		cout << "LibMat::~LibMat() destructor!\n";
	}

	virtual void print() const {
		cout << "LibMat::print() -- I am a LibMat object!\n";
	}
};

class Book : public LibMat {
public:
	Book( const string &title, const string &author )
		: _title( title ), _author( author ){
		cout << "Book::Book( " << _title
			 << ", " << _author << " )  constructor\n";
	}

	~Book(){
		cout << "Book::~Book() destructor!\n";
	}

	virtual void print() const {
		cout << "Book::print() -- I am a Book object!\n"
			 << "My title is: " << _title << '\n'
			 << "My author is: " << _author << endl;
	}

	const string& title() const { return _title; }
	const string& author() const { return _author; }

protected:
	string _title;
	string _author;
};

class AudioBook : public Book {
public:
	AudioBook( const string &title,
		       const string &author, const string &narrator )
		: Book( title, author ), _narrator( narrator ){
		cout << "AudioBook::AudioBook( " << _title
			 << ", " << _author
			 << ", " << _narrator
			 << " )  constructor\n";
	}

	~AudioBook(){
		cout << "AudioBook::~AudioBook() destructor!\n";
	}

	virtual void print() const {
		cout << "AudioBook::print() -- I am a AudioBook object!\n"
			 << "My title is: " << _title << '\n'
			 << "My author is: " << _author << '\n'
			 << "My narrator is: " << _narrator << endl;
	}

	const string& narrator() const { return _narrator; }

protected:
	string _narrator;
};

//void print( const LibMat &mat )
//{
//	cout << "in global print(): about to print mat.print()\n";
//	mat.print();
//}

int main()
{

	// objects are in local blocks to force destruction
	{
        cout << "\n" << "Creating a LibMat object to print()\n";
  	    LibMat m;
	    m.print();
	}

	{
        cout << "\n" << "Creating a Book object to print()\n";
	    Book b( "The Castle", "Franz Kafka" );
	    b.print();
	}

	{
        cout << "\n" << "Creating a AudioBook object to print()\n";
	    AudioBook ab( "Man Without Qualities", "Robert Musil", "Kenneth Meyer" );
	    ab.print();
	}

	return 0; // unnecessary but quiets vc++
}
//本代码改自《Essential C++》中文版P138-P142

运行结果:
《Essential C++》笔记之漫游:面向对象编程思维_第6张图片

例3( 例1代码中去掉了virtual void print() const

//小问学编程
#include 
#include 
#include 
using namespace std;

class LibMat {
public:
	LibMat(){
		cout << "LibMat::LibMat() default constructor!\n";
	}

	virtual ~LibMat(){
		cout << "LibMat::~LibMat() destructor!\n";
	}

//	virtual void print() const {
//		cout << "LibMat::print() -- I am a LibMat object!\n";
//	}
};

class Book : public LibMat {
public:
	Book( const string &title, const string &author )
		: _title( title ), _author( author ){
		cout << "Book::Book( " << _title
			 << ", " << _author << " )  constructor\n";
	}

	~Book(){
		cout << "Book::~Book() destructor!\n";
	}

//	virtual void print() const {
//		cout << "Book::print() -- I am a Book object!\n"
//			 << "My title is: " << _title << '\n'
//			 << "My author is: " << _author << endl;
//	}

	const string& title() const { return _title; }
	const string& author() const { return _author; }

protected:
	string _title;
	string _author;
};

class AudioBook : public Book {
public:
	AudioBook( const string &title,
		       const string &author, const string &narrator )
		: Book( title, author ), _narrator( narrator ){
		cout << "AudioBook::AudioBook( " << _title
			 << ", " << _author
			 << ", " << _narrator
			 << " )  constructor\n";
	}

	~AudioBook(){
		cout << "AudioBook::~AudioBook() destructor!\n";
	}

//	virtual void print() const {
//		cout << "AudioBook::print() -- I am a AudioBook object!\n"
//			 << "My title is: " << _title << '\n'
//			 << "My author is: " << _author << '\n'
//			 << "My narrator is: " << _narrator << endl;
//	}

	const string& narrator() const { return _narrator; }

protected:
	string _narrator;
};

void print( const LibMat &mat )
{
	cout << "in global print(): about to print mat.print()\n";
//	mat.print();
}

int main()
{

	// objects are in local blocks to force destruction
	{
        cout << "\n" << "Creating a LibMat object to print()\n";
  	    LibMat m;
	    print(m);
	}

	{
        cout << "\n" << "Creating a Book object to print()\n";
	    Book b( "The Castle", "Franz Kafka" );
	    print(b);
	}

	{
        cout << "\n" << "Creating a AudioBook object to print()\n";
	    AudioBook ab( "Man Without Qualities", "Robert Musil", "Kenneth Meyer" );
	    print(ab);
	}

	return 0; // unnecessary but quiets vc++
}
//本代码改自《Essential C++》中文版P138-P142

运行结果:
《Essential C++》笔记之漫游:面向对象编程思维_第7张图片

你可能感兴趣的:(小问《Essential,C++》笔记,小问C++笔记,c++)