• C++ Primer笔记14_面向对象程序设计


    版权声明:本文为博主原创文章,未经博主同意不得转载。 https://blog.csdn.net/scottly1/article/details/31371611

    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。而不会调用派生类的析构函数。


  • 相关阅读:
    mysql5.6 online ddl—索引
    lepus监控OS配置
    mysql字符集问题
    xtrabackup 2.0.8备份mysql5.1.65报错
    子网掩码值
    僵尸进程(待补充)
    libc.so.6重做链接,删除导致的缺失问题(后期需要深入研究),未能成功升级
    atlas
    ./encrypt: error while loading shared libraries: libcrypto.so.10:
    lepus bug
  • 原文地址:https://www.cnblogs.com/ldxsuanfa/p/10015492.html
Copyright © 2020-2023  润新知