c++ 继承 继承 的二义性 虚函数

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/liudao7994/article/details/82049131

其他知识

pragma once是一个比较常用的C/C++杂注,只要在头文件的最开始加入这条杂注,就能够保证头文件只被编译一次。

  • 父类里面没有默认的构造函数,那么子类里面也不能有默认的构造函数

例子1 继承的基本使用

父类 Plane 两个类: 一个是头文件 一个是源文件

#pragma once
#include <string>
class Plane
{
public:
    Plane();
    Plane(std::string name, int year);
    ~Plane();

    void fly();

    void land();

    void printf();

protected:
    std::string name;
    int year;
};



源文件

#include <Plane.h>
#include <iostream>
//#include <string>

using namespace std;

Plane::Plane() :name("F-22"), year(2010)
{
    cout << "Plane 无参(默认)的构造函数: 名字:" << name << " 生产年代:" << year << endl;
}
Plane::Plane(std::string name, int year) :name(name), year(year)
{
    cout << "Plane 的构造函数" << name << year << endl;
}

Plane::~Plane()
{
    cout << "Plane 的析构函数" << endl;
}

void Plane::fly(){
    cout << "Plane 的fly函数" << endl;
}

void Plane::land(){
    cout << "Plane 的land函数" << endl;
}

void Plane::printf(){
    cout << "Plane 的printf函数" << endl;
}

子类 两个文件 头文件 源文件

#pragma once
#include <Plane.h>
class Jet : public Plane
{
public:
    Jet();
    Jet(std::string name, int year);
    ~Jet();

private:

};

这里继承 使用: 来继承

源文件

#include <Jet.h>
#include <iostream>

using namespace std;
Jet::Jet()
{
    cout << "Jet 无参(默认)数的构造函数 名字: " << name << " 生产年代:" << year << endl;
}
Jet::Jet(std::string name, int year)
{
    cout << "Jet 参(默认)的构造函数: 名字:" << name << " 生产年代:" << year << endl;

}
Jet::~Jet()
{
    cout << "Jet 的析构函数" << endl;
}

主类 main 调用


#include <Plane.h>
#include <iostream>
#include <string>
#include <Jet.h>
using namespace std;

void func(){
    Jet jet;
    jet.fly();
}
void main(){
    func();
    system("pause");
}

打印结果 :

Plane 无参(默认)的构造函数: 名字:F-22 生产年代:2010
Jet 无参(默认)数的构造函数 名字: F-22 生产年代:2010
Planefly函数
Jet 的析构函数
Plane 的析构函数
请按任意键继续. . .

上面 jet.fly() 调用的是父类的方法, 没有在子类里声明任何方法

如果在子类 Jet里面定义和父类Plane里面相同的方法 那么调用的时候就是子类的方法.重写

如果已经重写了 那么

可以看到调用顺序

创建的时候 先调用父类的构造函数 释放时 先调用子类的析构函数

已经重写了父类的函数,但想调用父类的函数怎么调用

jet.Plane :: fly();

这样就调用了父类的函数.

下面调用的是父类的函数还是子类的函数


//派生类赋给父类
Plane *pl = &jet//指针
pl->fly();

Plane &p2 = jet;//对象
p2.fly();

结果调用的是父类的函数.

重载和重写

重载 参数不同函数名相同
重写 都相同

例子2 继承的二义性.多继承

class A
{
public:
    string name;
};

class A1: public A
{    
};

class A2 :  public A
{
};

//多继承的二义性 :只能显示使用根属性

//多继承用逗号分隔
class B : public A1, public A2
{


};

调用:


    B b;
    //b :: name = "test";// 如果直接调用会报错, 不知道使用的是A1还是A2的 name 这就是继承的二义性
    b.A1::name = "nameA1"; //只能显示调用
    b.A2::name = "nameA2";

如果想给父类的name赋值 ?

虚继承 virtual

// virtual 虚继承 : 解决路径不明确的问题,使多个继承的同名成员时候 只有一份拷贝
两个派生类

class A1:virtual public A
{    
};

class A2 : virtual public A
{
};

调用:


    B b;
    b : name = "test";// 如果直接调用 不知道使用的是A1还是A2的 name 继承的二义性
    b.A1::name = "nameA1"; //只能显示调用
    b.A2::name = "nameA2";

继承类型

当一个类派生自基类,该基类可以被继承为 public、protected 或 private 几种类型。继承类型是通过上面讲解的访问修饰符 access-specifier 来指定的。

我们几乎不使用 protected 或 private 继承,通常使用 public 继承。

详细看这里 http://www.runoob.com/cplusplus/cpp-inheritance.html

问题 父类的指针 指向 一个子类对象 导致内存泄露

//用父类的指针来new一个子类的对象
    Plane *jet = new Copter();
    //调用了子类中的虚函数
    jet->land();

    //回收
    delete jet;
    jet = nullptr;   //这种情况存在内存泄漏的可能

结果调用了父类的析构函数 但是没有调用子类的析构函数. 这个时怎么解决.

解决: 需要在父类的析构函数中加上virtual关键字

解析: 父类加上virtual关键字,那么子类里面默认也是加上了virtual.

相似代码参考
https://www.jianshu.com/p/c9055d8f66bc

纯虚函数

纯虚函数是在基类中声明的虚函数,它在基类中没有定义,但要求任何派生类都要定义自己的实现方法。在基类中实现纯虚函数的方法是在函数原型后加”=0”

virtual void funtion1()=0

实际就是定义个接口
参考资料
http://www.runoob.com/w3cnote/cpp-virtual-function.html

猜你喜欢

转载自blog.csdn.net/liudao7994/article/details/82049131