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


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

    //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";
    	}
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

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

    void print(const LibMat &mat)
    {
    	cout<<"in global print():about to print mat.print()\n";
    	//下一行会依据mat实际指向的对象
    	//解析该执行哪一个print()成员函数
    	mat.print();
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    //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);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    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;
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25

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

    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;
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29

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

    总结

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

    1. 三者的成员函数有重合之处,其中print()这一成员函数的具体实现各有不同,使用virtual关键字,以调用真正指向的对象的成员函数(虚拟调用);
    2. 使用:号和public实现派生类继承的标记,不必刻意区分“继承而来的成员”和“自身定义的成员",在其使用上无特别的不同之处;
    3. 被声明为protected的所有成员都可以被派生类直接访问;
      除了派生类之外,都不得直接访问protected成员。
    4. 当程序定义出一个派生对象,基类和派生类的构造函数都会被执行;
      当派生对象被销毁时,基类和派生类的析构函数也都会被执行,且执行顺序颠倒
  • 相关阅读:
    QT信号与槽/窗口组件优化/使用QT制作QQ登录界面
    Vue 项目中使用 Pinia 状态管理详细教程
    php+vue+Elementui大学生心理健康测评网站
    【红外图像增强】基于引力和侧向抑制网络的红外图像增强模型(Matlab代码实现)
    【图像分类】Swin Transformer理论解读+实践测试
    路由菜单路径匹配方法
    C#程序设计之windows应用程序设计基础
    c语言内存函数
    NCC Mocha v0.1.0 发布,.NET 开发的基于 OpenTelemetry 的 APM 系统
    千梦网创:实现自动化“挂机躺盈”的三种方法
  • 原文地址:https://blog.csdn.net/weixin_49347928/article/details/133587965