C++ 继承&多态

继承

当我们遇到两个功能相似缺仍有偏差的类,但是二者并不能互相代替,就可以使用继承手段,呈现了面向对象程序设计的层次结构,继承是类设计层次的复用

#include <iosteam>

#include <string>

using namespace std;

1.继承方式

class person                              //父类/基类

public:

{

        void print()                        //缺省也会被继承

{

        cout <<_name<<endl;
}

protected:

        string _name = 111;

        int _age = 11;

};

class student : public person    //student就是派生类/子类 public是继承方式

{

protected:

        int _stuid;

};

int main()

{

        student s;

}

继承方式有很三种,私有继承 保护继承 公有继承。大多数情况下都使用公有继承,不同的继承方式代表着对父类成员的范围权限。父类的私有成员无论怎么样都访问不了,公有继承时,三个都不变,保护继承时,公有变继承,其他两个不变,总结一下就是公有<保护<私有。

还有一小句就是保护可见,私有不可见,二者都不能用。

不写继承方式的时候,class默认是私有继承,struct默认是公有继承。

赋值转换

在我们把一个浮点型赋值给一个整型,会通过隐式类型转换这样一个过程,在类中,我们把一个子类赋值给一个父类,并不会有着什么转换之类的东西,他是”纯天然的“,父与子这种关系之间的赋值并不需要第三方作保障。

在赋值的时候,会把子类中的父类对象给新对象,子类中特有的并不会赋值到新对象中,所以这个过程也叫切片。子能给父,但是只有父类指针才可以给子(这个后面演示)。

作用域

当父类和子类有着同名成员或者同名函数,这个时候子类会把父类的重复东西给隐藏(重定义),访问的时候之后用子类的,父类的需要::显示访问就可以了。

只要函数名相同就构成隐藏/重定义。

派生类的默认成员函数

父类调用父类的那六个,子类调用子类的。(暂写)

但是在析构函数这里,顺序是按照与构造相反的顺序,并且在调用的时候不能显示实例化,因为会构成隐藏,然后父的析构会调用子的析构。

在构造派生类对象时,会先构造父类,才会构造子类,先析构子类,再去析构父类。

友元函数和静态成员

友元函数子类并不会继承,静态成员属于整个类,不存在继承概念。

//多继承和菱形继承

多态

概念 定义和实现

class person

{

public:

        virtual void buy(){ cout << "全价" << endl };
};

class student

{

public:
        virtual void buy(){ cout << "半价" << endl };

};

void func(person& p)

{

        p.buy;

}

int main()

{

        person ps;

        student st;

        func(ps);

        func(st);

        return 0;

}

以上这段代码就体现了多态,会输出全价和半价。

重写/覆盖:

1.被virtual修饰的就是虚函数 

2.虚函数可以说就是为了重写而生的,函数名 参数 返回值,这三样相同并且有virtual修饰

3.子类的虚函数可以省略virtual(接口继承,会继承父类的virtual)一般不省略

4.父指针的指针或者引用调用(后面的注释请读完虚表再看)(如果时普通对象,在切片的时候会把虚表也拷贝回去,而指针或者引用只会拷贝除了虚表和切完的对象,如果把虚表也拷贝回去,父类会有属于不属于他的东西,调用出错就会很懵)

只有满足以上条件才会有所谓的虚函数

不满足多态时(virtual没有修饰父类函数)调用调用者类型的1成员函数。

其实有一个例外,但是这个例外很少见,就是协变——返回值可以不同,但是有个前提就是返回值必须是父子关系指针或者引用。

final:在父类虚函数名后加上这个修饰词,表示该函数不可被继承。

override:位置同上,会检查该函数是否满足多态(以报错提醒)。

抽象类

在虚函数后边直接写上=0,这个函数就叫纯虚函数,有纯虚函数的类就叫抽象类,抽象类不能实例化出对象。重写的函数才能实例化出对象。 

用途可以强制子类重写。

原理和虚函数表

class base

{

public:

virtual void func()

{

        cout << func << endl;

}

private:

        int _b;

        char _a;

}

大家可以先算一下这里base的指针,显而易见,一个int一个char加上整形对齐就是8,但实际算出来的结果却是12,他是多态嘛,自然多了点不一样的,这一样就是虚函数表指针。

要不然怎么说不同的函数经过相同父类的引用或者指针传参调用时会产生不同的结果啊,这就解释通了,调用时访问虚函数表指针去访问虚函数表里的虚函数来覆盖调用的函数,所以重写也有另一个名字,叫做覆盖。

虚函数表本质就是虚函数指针数组,是一个数组,去存储那些虚函数的指针,以此来调用虚函数。

虚表在编译时产生,构造函数初始化列表的时候被初始化,大概率存在代码段(常量区)。

//多继承多态偏移量

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值