面向对象的C++了解


面向对象
封装基础上了解C++的继承、多态;
了解什么叫做继承,继承方式,继承内容,如何使用继承。

了解C++

继承

继承定义

  1. 定义:
    a. 面向对象程序设计中最重要的一个概念是继承。继承允许我们依据另一个类来定义一个类,这使得创建和维护一个应用程序变得更容易。这样做,也达到了重用代码功能和提高执行效率的效果。
    b. 当创建一个类时,您不需要重新编写新的数据成员和成员函数,只需指定新建的类继承了一个已有的类的成员即可。
    这个已有的类称为基类,新建的类称为派生类。
    c. 继承代表了 is a 关系。例如,哺乳动物是动物,狗是哺乳动物,因此,狗是动物,等等。

    class 基类名{};
    class 派生类名: pulbic 基类名{//public private protected
         //派生类新增的数据成员和成员函数
    };
    //____多继承___
    class <派生类名>:<继承方式1><基类名1>,<继承方式2><基类名2>,{
    <派生类类体>
    };
    
  2. 继承权限+访问权限
    图片来源:传智博客
    在这里插入图片描述

继承内容

继承中的构造与析构函数(不会被继承)

  1. 调用(构造和重名调用不同)
    b. 子类对象在创建时会首先调用父类的构造函数
    c. 父类构造函数执行完毕后,才会调用子类的构造函数
    d. 当父类构造函数有参数时,需要在子类初始化列表(参数列表)中显示调用父类构造函数
    e. 析构函数调用顺序和构造函数相反

    #include <iostream>
    #include <string>
    using namespace std;
    class A
    {
    public: 
    	int a;
    	A(int a)
    	{
    		cout << a <<"A"<< endl;
    	}
    protected: int b;
    private: int c;
    };
    class B :public A//public |->protected |->private
    {
    public:
    	B(int a) :A(a)
    	{
    		cout << a << "b" << endl;
    	}
    
    };
    
    void main()
    {
    	B b(2);
    	system("pause");
    }
    

在这里插入图片描述

  1. 继承中构造和析构函数调用顺序;类嵌套构造函数和析构函数调用顺序这里记忆
    网络图

  2. 继承中的父子重名
    父子方法重名,子类会隐藏父类(包括父类重写,如果想要调用父类的方法,需要注明作用域。)
    成员属性与方法一样

    son.fun();//重名子类方法
    son.father::fun();//重名父类方法
    
  3. static静态成员处理,静态成员属性可以继承。静态成员函数和非静态成员函数的共同点:a.他们都可以被继承到派生类中。b.如果重新定义一个静态成员函数,所有在基类中的其他重载函数会被隐藏。c.如果我们改变基类中一个函数的特征,所有使用该函数名的基类版本都会被隐藏。静态成员函数不能是虚函数(virtual function)

  4. 多继承 ,多继承容易让代码逻辑复杂、思路混乱,一直备受争议,中小型项目中较少使用,后来的 Java、C#、PHP 等干脆取消了多继承。菱形继承二义性问题虚继承(继承虚基类)解决 virtual。工程开发中真正意义上的多继承是几乎不被使用,因为多重继承带来的代码复杂性远多于其带来的便利,多重继承对代码维护性上的影响是灾难性的,在设计方法上,任何多继承都可以用单继承代替。

    class BigBase{
    public:
    	BigBase(){ mParam = 0; }
    	void func(){ cout << "BigBase::func" << endl; }
    public: int mParam;
    };
    #if 0 //虚继承
    class Base1 : virtual public BigBase{};
    class Base2 : virtual public BigBase{};
    #else //普通继承
    class Base1 :  public BigBase{};
    class Base2 :  public BigBase{};
    #endif
    class Derived : public Base1, public Base2{};
    
  5. 类嵌套、类继承构造和析构函数的调用顺序;重载函数、 重名函数调用。

    区别类嵌套类继承
    定义class A {class B{};};class A{}; class B:public A{};
    造析构函数调用顺序Ag、Bg、Bx、AxAg、Bg、Bx、Ax
    间访问权限可以看以前博客也可以看网络

    重载、重写、重定义

    区别重载重写(覆盖)重定义(隐藏)
    数名相同相同相同
    用域同一作用域子类父类子类父类
    不同相同不同1
    回值可以不同相同不同2

多态

c++支持编译时多态(静态多态重载)和运行时多态(动态多态),运算符重载和函数重载就是编译时多态,而派生类和虚函数实现运行时多态。

  1. 父类指针、引用指向子类对象---->多态:

    	#include <iostream>
    	#include <string>
    	using namespace std;
    	class Animal {
    	public:
    		void speak() {
    			cout << "动物在唱歌..." << endl;
    		}
    	};
    	class Dog : public Animal {
    	public:
    		void speak() {
    			cout << "小狗在唱歌..." << endl;
    		}
    	};
    	void DoBussiness(Animal& animal) {
    		animal.speak();//speak函数类型已经绑定好了(静态联编,未运行编译阶段便确定了地址)
    		//将静态链接改变为动态链接,父类声明virtual,子类中可写可不写(建议写增加可读性)
    	}
    	void test() {
    		Dog dog;
    		DoBussiness(dog);
    	}
    	void main()
    	{
    		test();
    		system("pause");
    	}
    

    运行结果: 动物在唱歌
    问题抛出: 我们给DoBussiness传入的对象是dog,而不是animal对象,输出的结果应该是Dog::speak。
    问题解决:virtual 虚函数解决

    class Animal{
    public:
    	virtual void speak(){//虚函数virtual
    		cout << "动物在唱歌..." << endl;
    	}
    };
    class Dog : public Animal{
    public:
    	virtual void speak(){
    		cout << "小狗在唱歌..." << endl;
    	}
    };
    void DoBussiness(Animal& animal){
    	animal.speak();
    }
    void test(){
    	Dog dog;
    	DoBussiness(dog);
    }
    

    virtual关键字使得class内部结构改变,virtual 增加了一个指针vfptr(virtual funtion pointer)指向虚函数表;继承时:构造函数执行,所有虚函数表指针指向自身虚函数表(此操作看不到);自身虚函数表覆盖(重写)继承的虚函数表。

    Animal * animal = new Cat;//父类指针指向子类
    animal.speak();
    //函数内部结构
    *(int *)*(int *)animal;//函数地址
    void(*)()//函数指针
    (void(*)() (*(int*)*(int *)animal)) ();//函数调用
    /*
    重写原理: 
    当父类有virtual关键字定义的虚函数时,内部多了一个vfptr指针,vfptr指向了虚函数表;
    父类中结构 vtptr  &animal::peak;子类中进行继承,会继承虚函数表;
    构造函数中,会构造虚函数指针,指向自己的虚函数表;
    如果发生了重写,会替换虚函数表中的speak 为&cat::speak;
    */
    

    指针 指针指向的表生成,重写(覆盖)。
    扩展开发,修改关闭!父类指针指向子类对象

  2. 纯虚函数(virtual+普通函数)
    a. 如果父类中有纯虚函数,那么子类继承必须要实现纯虚函数;
    b. 如果父类中有纯虚函数,那么此函数无法实例化(相当于一个声明);
    c. 如果类中有纯虚函数,又称抽象类。

  3. 虚析构函数

    虚析构纯虚析构
    virtual ~ 类名(){};声明实现不限类内声明  virtual~ 类名()=0 ; 类外实现  A::~A(){}
    过父类指针指向子类对象释放不干净导致的问题; 不影响实例化出现纯虚构函数,默认为抽象类,不可以实例化对象
  4. 转型

    向下转型
    向上转型
    向下转型
    向上转型
    父类
    子类
    子类
    向下转型向上转型
    父类转子类(基类转派生类)子类转父类(派生类转基类)
    不安全安全

    如果多态() 都是安全的


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Echo一

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值