c++继承

目录

1.继承的基本概念

使用继承的场景:

示例:

2、继承方式

继承方式有三种

示例:

3、继承的对象模型

查看对象内存布局的方法:

示例:


1.继承的基本概念

概括:从继承开始就是对代码进行复用的学习,继承可以理解为一个类从另一个类获取成员变量和成员函数的过程。目的是重复使用代码。

class 派生类名:[继承方式]基类名

{

    派生类新增加的成员

};

被继承的类称为基类或父类,继承的类称为派生类或子类。

继承和派生是一个概念,只是站的角度不同。

派生类除了拥有基类的成员,还可以定义新的成员,以增强其功能。

使用继承的场景:

1) 如果新创建的类与现有的类相似,只是多出若干成员变量或成员函数时,可以使用继承。

2) 当需要创建多个类时,如果它们拥有很多相似的成员变量或成员函数,可以将这些类共同的成员提取出来,定义为基类,然后从基类继承。

示例:

#include <iostream>         // 包含头文件。
using namespace std;        // 指定缺省的命名空间。
           
class CAllComers          // 海选报名者类
{           
public:
    string    m_name;    // 姓名
    string    m_tel;         // 联系电话
                 
    // 构造函数。
    CAllComers() { m_name = "某女"; m_tel = "不详"; }
    // 报名时需要唱一首歌。
    void sing() { cout << "我是一只小小鸟。\n"; }
    // 设置姓名。
    void setname(const string& name) { m_name = name; }
    // 设置电话号码。
    void settel(const string& tel) { m_tel = tel; }
};     
         
class CGirl :public CAllComers        // 超女类
{           
public:
    int m_bh;          // 编号。
    CGirl() { m_bh = 8;  }
    void show() { cout << "编号:" << m_bh << ",姓名:" << m_name << ",联系电话:" << m_tel << endl; }
};           
             
int main()
{        
    CGirl g;
    g.setname("西施");
    g.show();
}

2、继承方式

类成员的访问权限由高到低依次为:public --> protected --> privatepublic成员在类外可以访问,private成员只能在类的成员函数中访问。

如果不考虑继承关系,protected成员和private成员一样,类外不能访问。但是,当存在继承关系时,protectedprivate就不一样了。基类中的protected成员可以在派生类中访问,而基类中的 private成员不能在派生类中访问。

继承方式有三种

public(公有的)、protected(受保护的)和private(私有的)。它是可选的,如果不写,那么默认为private。不同的继承方式决定了在派生类中成员函数中访问基类成员的权限。

     

 

1)基类成员在派生类中的访问权限不得高于继承方式中指定的权限。例如,当继承方式为protected时,那么基类成员在派生类中的访问权限最高也为protected,高于protected的会降级为protected,但低于protected不会升级。再如,当继承方式为public时,那么基类成员在派生类中的访问权限将保持不变。

也就是说,继承方式中的public、protected、private是用来指明基类成员在派生类中的最高访问权限的。

2) 不管继承方式如何,基类中的private成员在派生类中始终不能使用(不能在派生类的成员函数中访问或调用)。

3) 如果希望基类的成员能够被派生类继承并且毫无障碍地使用,那么这些成员只能声明为public 或protected;只有那些不希望在派生类中使用的成员才声明为private。

4) 如果希望基类的成员既不向外暴露(不能通过对象访问),还能在派生类中使用,那么只能声明为 protected。

由于private和protected继承方式会改变基类成员在派生类中的访问权限,导致继承关系复杂,所以,在实际开发中,一般使用public

在派生类中,可以通过基类的公有成员函数间接访问基类的私有成员。

使用 using 关键字可以改变基类成员在派生类中的访问权限。

注意:using只能改变基类中public和protected成员的访问权限,不能改变private成员的访问权限,因为基类中的private成员在派生类中是不可见的,根本不能使用。

示例:

#include <iostream>         // 包含头文件。

using namespace std;        // 指定缺省的命名空间。



class A  {        // 基类

public:

    int m_a=10;

protected:

    int m_b=20;

private:

    int m_c = 30;

};



class B :public A        // 派生类

{

public:

    using A::m_b;         // 把m_b的权限修改为公有的。

private:

    using A::m_a;         // 把m_a的权限修改为私有的。

};



int main()

{

    B b;  

    // b.m_a = 11;

    b.m_b = 21;

    //b.m_c = 21;

}

3、继承的对象模型

1)创建派生类对象时,先调用基类的构造函数,再调用派生类的构造函数。

2)销毁派生类对象时,先调用派生类的析构函数,再调用基类的析构函数。如果手工调用派生类的析构函数,也会调用基类的析构函数。

3)创建派生类对象时只会申请一次内存,派生类对象包含了基类对象的内存空间,this指针相同的。

4)创建派生类对象时,先初始化基类对象,再初始化派生类对象。

5)在VS中,用cl.exe可以查看类的内存模型。

6)对派生类对象用sizeof得到的是基类所有成员(包括私有成员)+派生类对象所有成员的大小。

7)在C++中,不同继承方式的访问权限只是语法上的处理。

8)对派生类对象用memset()会清空基类私有成员。

9)用指针可以访问到基类中的私有成员(内存对齐)。

查看对象内存布局的方法:

cl 源文件名 /d1 reportSingleClassLayout类名

注意:类名不要太短,否则屏幕会显示一大堆东西,找起来很麻烦。

例如,查看BBB类,源代码文件是demo01.cpp:

cl demo01.cpp /d1 reportSingleClassLayoutBBB

cl命令环境变量:

1)在PATH环境变量中增加cl.exe的目录

C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Tools\MSVC\14.30.30705\bin\Hostx64\x64

2)增加INCLUDE环境变量,内容如下:

C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Tools\MSVC\14.30.30705\include

C:\Program Files (x86)\Windows Kits\10\Include\10.0.19041.0\shared

C:\Program Files (x86)\Windows Kits\10\Include\10.0.19041.0\ucrt

C:\Program Files (x86)\Windows Kits\10\Include\10.0.19041.0\um

C:\Program Files (x86)\Windows Kits\10\Include\10.0.19041.0\winrt

3)增加LIB环境变量,内容如下:

C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Tools\MSVC\14.30.30705\lib\x64

C:\Program Files (x86)\Windows Kits\10\Lib\10.0.19041.0\um\x64

C:\Program Files (x86)\Windows Kits\10\Lib\10.0.19041.0\ucrt\x64

示例:

#include <iostream>         // 包含头文件。

using namespace std;        // 指定缺省的命名空间。

           

void* operator new(size_t size)   // 重载new运算符。

{

    void* ptr = malloc(size);        // 申请内存。

    cout << "申请到的内存的地址是:" << ptr << ",大小是:" << size << endl;

    return ptr;

}

              

void operator delete(void* ptr)   // 重载delete运算符。

{

    if (ptr == 0) return;       // 对空指针delete是安全的。

    free(ptr);      // 释放内存。

    cout << "释放了内存。\n";

}

             

class A {        // 基类

public:

    int m_a = 10;

protected:

    int m_b = 20;

private:

    int m_c = 30;

public:

    A() {

        cout << "A中this指针是: " << this << endl;

        cout << "A中m_a的地址是:" << &m_a << endl;

        cout << "A中m_b的地址是:" << &m_b << endl;

        cout << "A中m_c的地址是:" << &m_c << endl;

    }

    void func() { cout << "m_a=" << m_a << ",m_b=" << m_b << ",m_c=" << m_c << endl; }

};

                

class B :public A        // 派生类

{

public:

    int m_d = 40;

    B() {

        cout << "B中this指针是: " << this << endl;

        cout << "B中m_a的地址是:" << &m_a << endl;

        cout << "B中m_b的地址是:" << &m_b << endl;

        //cout << "B中m_c的地址是:" << &m_c << endl;

        cout << "B中m_d的地址是:" << &m_d << endl;

    }

    void func1() { cout << "m_d=" << m_d << endl; }

};

               

int main()

{

    cout << "基类占用内存的大小是:" << sizeof(A) << endl;

    cout << "派生类占用内存的大小是:" << sizeof(B) << endl;

             

    B *p=new B;

    p->func(); p->func1();

    // memset(p, 0, sizeof(B));

    *((int*)p + 2) = 31;        // 把基类私有成员m_c的值修改成31。

    p->func(); p->func1();

    delete p;

}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值