【C++】面向对象编程(二)面向对象的编程思维:virtual虚拟调用、继承、protected成员、派生类与基类

默认情形下,成员函数的解析都是编译时静态进行。如果要让成员函数的解析在程序运行时动态进行,需要在成员函数的声明前加上关键字virtual:

cpp 复制代码
//LibMat声明表示,其析构函数和print()函数皆为虚函数
class LibMat{
public:
	LibMat()
	{
		cout<<"LibMat::LibMat() default constructor!\m";
	}
	virtual ~LibMat()
	{
		cout<<"LibMat::~LibMat() destructor!\n";
	}
	virtual void print()const
	{
		cout<<"LibMat::print()--I am a LibMat object!\n";
	}
};

虚函数的作用:

用基类的指针指向不同的派生类的对象时,基类指针调用其虚成员函数,会调用真正指向对象的成员函数 ,而不是基类中定义的成员函数;若不是虚函数,则只会调用基类中定义的那个函数

cpp 复制代码
void print(const LibMat &mat)
{
	cout<<"in global print():about to print mat.print()\n";
	//下一行会依据mat实际指向的对象
	//解析该执行哪一个print()成员函数
	mat.print();
}
cpp 复制代码
//main函数中重复调用print()
//并依次将三个对象作为参数传递给它
//每次执行
int main()
{
	cout<<"\n"<<"Creating a LibMat object to print()\n";
	LibMat libmat;
	print(libmat);
	
	cout<<"\n"<<"Creating a Book object to print()\n";
	Book b("The Castle","Franz Kafka");
	print(b);

	cout<<"\n"<<"Creating an AudiBook = object to print()\n";
	AudioBook ab("Man without Qualities","Robert Musil","Kenneth Meyer");
	print(ab);
}
cpp 复制代码
class Book : public LibMat {  //定义派生类Book,继承自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;
};

被声明为protected的所有成员都可以被派生类直接访问;除了派生类之外,都不得直接访问protected成员。

cpp 复制代码
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;
};

派生类的构造函数作用后顺序:
基类的构造函数、派生类的析构函数、基类的析构函数。

总结

示例中分别实现了三种类:LibMatBookAudioBook

  1. 三者的成员函数有重合之处,其中print()这一成员函数的具体实现各有不同,使用virtual关键字,以调用真正指向的对象的成员函数(虚拟调用);
  2. 使用:号和public实现派生类继承的标记,不必刻意区分"继承而来的成员"和"自身定义的成员",在其使用上无特别的不同之处;
  3. 被声明为protected的所有成员都可以被派生类直接访问;
    除了派生类之外,都不得直接访问protected成员。
  4. 当程序定义出一个派生对象,基类和派生类的构造函数 都会被执行;
    当派生对象被销毁时,基类和派生类的析构函数 也都会被执行,且执行顺序颠倒
相关推荐
1104.北光c°1 分钟前
滑动窗口HotKey探测机制:让你的缓存TTL更智能
java·开发语言·笔记·程序人生·算法·滑动窗口·hotkey
for_ever_love__1 小时前
Objective-C学习 NSSet 和 NSMutableSet 功能详解
开发语言·学习·ios·objective-c
仰泳的熊猫4 小时前
题目2570:蓝桥杯2020年第十一届省赛真题-成绩分析
数据结构·c++·算法·蓝桥杯
似水明俊德7 小时前
02-C#.Net-反射-面试题
开发语言·面试·职场和发展·c#·.net
Thera7778 小时前
C++ 高性能时间轮定时器:从单例设计到 Linux timerfd 深度优化
linux·开发语言·c++
炘爚9 小时前
C语言(文件操作)
c语言·开发语言
阿蒙Amon9 小时前
C#常用类库-详解SerialPort
开发语言·c#
凸头9 小时前
CompletableFuture 与 Future 对比与实战示例
java·开发语言
wuqingshun3141599 小时前
线程安全需要保证几个基本特征
java·开发语言·jvm
君义_noip9 小时前
信息学奥赛一本通 1952:【10NOIP普及组】三国游戏 | 洛谷 P1199 [NOIP 2010 普及组] 三国游戏
c++·信息学奥赛·csp-s