c++继承

本文深入讲解C++中的继承概念,包括继承的定义、语法、成员访问权限、对象模型、构造顺序以及基类与派生类中同名成员的处理方式。通过实例演示,帮助读者理解如何正确使用继承。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1、继承是什么

继承是代码的复用,被继承的类称为基类(父类),继承的新类叫派生类(子类)。
继承的类拥有父类的所有成员变量和成员函数,相当于类的完全复制。

2、继承的语法

class 新类名 :访问控制 要继承的类
例如:class new:public old------>new类继承了old类。

#include <iostream>
#include <string>

using namespace std;

//父类(基类)
class people
{
public:
    void eat()
    {
        cout<<"吃饭"<<endl;
    }
    void slee()
    {
        cout<<"睡觉"<<endl;
    }

public:
    int id;
    string name;
    string sex;
};

//子类(派生类)
class student:public people
{
public:
    void study()
    {
        cout<<"学习"<<endl;
    }
};

class worker:public people
{
public:
    void work()
    {
        cout<<"工作"<<endl;
    }
};

int main1()
{
    student s;
    s.study();

    worker w;
    w.work();

    return 0;
}

3、基类成员在派生类中的访问权限

min(基类中的权限,继承时的访问限制)
其中:public>protected>private
1、对于 public的访问权限,基类中对应访问权限在派生类的情况
public:类的内部和外部都能使用。
protected:在类内部可以使用,在外部不能使用。
private:在类的内部和外部都不能使用。
2、对于 protected的访问权限,基类中对应访问权限在派生类的情况
public:在类内部可以使用,在外部不能使用
protected:在类内部可以使用,在外部不能使用。
private:在类的内部和外部都不能使用。
3、对于 private的访问权限,基类中对应访问权限在派生类的情况
public:在类内部可以使用,在外部不能使用
protected:在类内部可以使用,在外部不能使用。
private:在类的内部和外部都不能使用。
对于protected与private访问权限的区别:
在二次或多次继承后,protected的访问权限能在类内部使用,private的访问权限不能在类内部使用。

class Parent
{
public:
    Parent(int var = -1)
    {

    }
public:
    int m_nPub;
protected:
    int m_nPtd;
private:
    int m_nPrt;
};


class Child1:public Parent
{
public:
    int getPub() {return m_nPub;}
    int getPtd() {return m_nPtd;}
        int getPrt() {return m_nPrt;}   // A   错
};

class Child2:protected Parent
{
public:
    int getPub() {return m_nPub;}
    int getPtd() {return m_nPtd;}
        int getPrt() {return m_nPrt;}   // B   错
};

class Child3:private Parent
{
public:
    int getPub() {return m_nPub;}
    int getPtd() {return m_nPtd;}
        int getPrt() {return m_nPrt;}   // C   错
};

int main()
{
    Child1 cd1;
    Child2 cd2;
    Child3 cd3;

    int nVar = 0;
        cd1.m_nPub = nVar;    // D          对
        cd1.m_nPtd = nVar;    // E          错
        nVar = cd1.getPtd();  // F          对

        cd2.m_nPub = nVar;    // G          错
        nVar = cd2.getPtd();  // H          对

        cd3.m_nPub = nVar;    // I          错
        nVar = cd3.getPtd();  // J          对
    return 0;
}

4、对象模型(类型的兼容性原则)

1、一般情况下派生类对象可以替换基类对象
2、基类指针可以操作派生类对象(指针能做的事情与指向对象无关,之于本身的类型有关)
3、因为引用的本质是指针,因此基类引用可以引用派生类对象。
4、可以用派生类对象对基类对象构造(内部调用拷贝构造)和赋值(调用=运算符重载)

// 1、父类对象存在的地方都能用派生类对象进行替换
int main()
{
    parent p;
    p.getp(1,2);
    child c;
    c.getp(2,3);
    c.showp();


    return 0;
}

// 2、基类指针可以操作派生类对象
int main2()
{
    child c;
    parent *pa = &c;

    // 指针能做的事情基于指针本身的类型,和他指向的对象类型无关
    pa->getp(3,4);
    pa->showp();

    // 3、可以用基类的引用引用派生类对象
    parent &p3 = c; // Parent *const p3 = &c1
    p3.showp();

    return 0;
    return 0;
}

// 4、可以用派生类对象对基类对象进行构造、赋值
int main()
{
    child  c1;
    c1.getp(1,2);
    c1.getc(3,4);

    // Parent(const Parent &obj)
    parent p1 = c1;  //  ===>  p1的拷贝 构造函数
    p1.showp();

    // operator =(const Parent &obj)
    p1 = c1;  // 赋值运算符重载函数
    p1.showp();

    return 0;
}

5、对象的构造

1、原则:谁的成员由谁对其负责初始化---->调用相应构造函数---->在初始化列表中
2、构造的顺序:
(1、先调用基类的构造函数,对基类成员进行构造。
(2、调用自身的构造函数,对其成员进行构造。
(3、析构的顺序与其相反。

#include <iostream>

using namespace std;

// 对象的构造: 谁的成员谁负责初始化 --->  手动调用相应的构造函数 ---> 在对象初始化列表中
class Parent
{
public:
    Parent()
    {
        cout << "无参构造" << endl;
    }
    Parent(int a, int b)
    {
        cout << "Parent(int a, int b) 构造函数" << endl;
        m_a = a;
        m_b = b;
    }

protected:
    int m_a;
    int m_b;
};

class Test
{
public:
    Test(int a, int b)
    {
        cout << "test 构造函数" << endl;
    }
private:
    int m_a;
    int m_b;
};

// 继承中的构造顺序:1、先调用基类的构造函数对基类成员进行初始化 2、再调用自己的构造函数对象自己的成员进行初始化---->类似前置递归
// 继承中的析构顺序:和构造顺序相反---->类似后置递归
class Child : public Parent
{
public:
    Child(int a, int b, int c, int d): t1(c, d), Parent(a, b), m_c(c), m_d(d)
    {
        cout << "Chil 构造函数" << endl;
        //m_a = a;
        //m_b = b;
        m_c = c;
        m_d = d;
    }
protected:
    int m_c;
    int m_d;

    Test t1;
};

int main()
{
    Parent p1(1,2);

    Child c(1,2,3,4);

    return 0;
}

class A
{
public:
    A()
    {
        cout << "A 的构造*****************" << endl;
    }

    ~A()
    {
        cout << "A 的析构-----------------" << endl;
    }

};

class B : public A
{
public:
    B()
    {
        cout << "B 的构造*****************" << endl;
    }
    ~B()
    {
        cout << "B 的析构-----------------" << endl;
    }
};

class C : public B
{
public:
    C()
    {
        cout << "C的构造*****************" << endl;
    }

    ~C()
    {
        cout << "C 的析构-----------------" << endl;
    }

};

class D : public C
{
public:
    D()
    {
        cout << "D 的构造*****************" << endl;
    }

    ~D()
    {
        cout << "D 的析构-----------------" << endl;
    }

};

6、基类与派生类中同名成员的处理方式

1、如果基类与派生类中有同名成员,满足就近原则,默认使用的是派生类中的成员
2、基类同名成员的使用:派生类对象 基类类名::同名成员变量。
3、基类与派生类不能同时重载一个函数,函数重载只能发生在一个类中,如果派生类重载了基类中的函数,会将基类中的重载函数全部屏蔽。尽量不要在派生类中重载基类的函数。
4、函数重定义:派生类中的函数原型与基类中的函数原型一致。
5、对于基类中的静态成员变量,所有派生类对象都可以使用。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值