C++ 继承

在面向对象编程(OOP)中,继承是实现代码复用和层次结构的关键机制。相对于我们日常讨论的面向对象编程,继承体现了类之间的父子关系,即派生类(子类)可以继承基类(父类)的属性和行为,并对其进行扩展或重写。

基础语法

dog对象继承于基类 animal,可以通过继承关系来访问基类函数或者是成员对象

继承关系

 C++ 支持三种类型的继承方式:公有继承、保护继承和私有继承  ( public , protected , private),不同的继承方式会影响基类成员在派生类中的访问权限。

//基类
class Animal {
public:
    void cry() {
        cout << "Animal cry..." << endl;
    }

protected:
    string _type = "Animal";

private:
    string _animal = "_animal";
};

public 继承

公有继承是最常见的继承方式,基类中的publicprotected 成员在派生类中保持其访问级别不变。

class DogPublic : public Animal {
public:
    void showType() {
        cout << "Type: " << _type << endl;  // 可以访问基类的 protected 成员
        cry();  // 可以调用基类的 public 成员函数
    }

    // 提供公有方法来访问基类成员
    void callCry() {
        cry();  // 可以访问基类的 public 成员函数
    }
};

int main()
{
    DogPublic d;
    d.showType();
    d.callCry();
    d.cry();
    return 0;
}

在上述代码中,我们可以看出 ,public继承可以在派生类函数里访问 public 和 protected 成员 ,在类外可以调用基类方法。

protected 继承和 private 继承

为什么要把这两种继承写到一起呢,因为刚开始我对这两种继承了解并不深,想了半天他了继承的区别,最后发现,protected这个限定符就是为了某些基类定义的值,不想让派生类可以在类外调用,但是可以在类内部调用,那也就是说,他就这一个作用,其他我并没有看出有什么区别

class DogProtected : protected Animal {
public:
    void showType() {
        cout << _type << endl;

        cout << "Type: " << _type << endl;  // 可以访问基类的 protected 成员
        cry();  // 可以调用基类的 public 成员函数
    }

    // 提供公有方法来访问基类成员
    void callCry() {
        cry();  // 可以访问基类的 public 成员函数
    }
};

class DogPrivate : private Animal {
public:
    void showType() {
        cout << _type << endl;

        cout << "Type: " << _type << endl;  // 可以访问基类的 protected 成员
        cry();  // 可以调用基类的 public 成员函数
    }

    // 提供公有方法来访问基类成员
    void callCry() {
        cry();  // 可以访问基类的 public 成员函数
    }
};

类外都无法访问,只能通过类内方法进行访问

private定义的成员无论哪种继承都无法访问,由于protected 继承和 private 继承对于派生类等待使用限制较大,在开发中public使用较多,同时如果我们不限定继承方式,使用关键字class时默认的继承方式是private,使用struct时默认的继承方式是public,不过 最好显示的写出继承方式。

派生类的默认成员函数

Base为基类  Derived是派生类

在 C++ 中,派生类的默认成员函数包括构造函数、析构函数、拷贝构造函数和赋值运算符。这些默认成员函数有一些特殊的行为和规则

构造函数

上面我们说了,基类的private对象是无法被访问的,那么我们如何对其进行赋值呢,

//基类构造函数
Base(int value) : _value(value) {
    cout << "Base parameterized constructor" << endl;
}

//派生类构造函数
Derived(int baseValue, int derivedValue) : Base(baseValue), _derivedValue(derivedValue) {
    cout << "Derived parameterized constructor" << endl;
}

在派生类的构造函数里调用基类构造函数进行赋值

析构函数

~Base() {
    cout << "Base destructor" << endl;
}

~Derived() {
    cout << "Derived destructor" << endl;
}

析构函数很特殊,我们直接看是看不出区别的,这需要C++继承中的多态-CSDN博客来理解!!

 拷贝构造函数

拷贝构造函数也一样,我们需要调用基类的拷贝构造函数来对基类那部分数据进行拷贝构造

 Base(int value) : _value(value) {
     cout << "Base parameterized constructor" << endl;
 }

Derived(const Derived& other) : Base(other), _derivedValue(other._derivedValue) {
    cout << "Derived copy constructor" << endl;
}

赋值运算符

Base& operator=(const Base& other) {
    if (this != &other) {
        _value = other._value;
        cout << "Base assignment operator" << endl;
    }
    return *this;
}

Derived& operator=(const Derived& other) {
    if (this != &other) {
        Base::operator=(other);  //构成隐藏,显示调用
        _derivedValue = other._derivedValue;
        cout << "Derived assignment operator" << endl;
    }
    return *this;
}

如果实现了派生类的重载了赋值运算符,那么一定要实现基类赋值运算符的重载

基类对象与派生类对象的类型转换

在 C++ 中,派生类对象可以赋值给基类对象,称为对象的切割。当一个派生类对象赋值给基类对象时,只有基类部分被保留下来,而派生类的扩展部分被切割掉。

class Base {
public:
    void show() {
        std::cout << "Base show()" << std::endl;
    }
};

class Derived : public Base {
public:
    void display() {
        std::cout << "Derived display()" << std::endl;
    }
};

int main() {
    Derived d;
    Base b = d;  // 对象切割,基类部分被保留
    b.show();    // 输出:Base show()
    // b.display();  // 错误,无法访问派生类的方法
}

基类对象不能赋值给派生类对象。因为 派生类对象是对基类的扩展,会包含基类需要的所有数据,但是基类对象并不包含派生类所有成员需要的数据

子类对象内基类对象的创建与销毁时间

在 C++ 中,派生类对象的创建过程首先是基类对象的构造,然后是派生类对象的构造;而销毁过程则是相反的顺序:首先销毁派生类对象,然后销毁基类对象。也就是说,基类的构造先于派生类,基类的析构晚于派生类。 

class Base {
public:
    Base() {
        std::cout << "Base constructor" << std::endl;
    }
    ~Base() {
        std::cout << "Base destructor" << std::endl;
    }
};

class Derived : public Base {
public:
    Derived() {
        std::cout << "Derived constructor" << std::endl;
    }
    ~Derived() {
        std::cout << "Derived destructor" << std::endl;
    }
};

int main() {
    Derived d;
    return 0;
}

我们可以使用这段代码演示 

继承中的友元与 static 成员

友元函数与继承

class Base {
    friend void show(Base&);  // 基类的友元函数
protected:
    int x;
};

class Derived : public Base {
public:
    void display() {
        // show() 无法访问 Derived 的成员,除非显式声明友元
    }
};

C++ 中的友元函数不会被继承。也就是说,如果基类中定义了一个友元函数,这个函数在派生类中不会自动成为友元,必须显式声明友元关系。

static 成员与继承

class Base {
public:
    static int count;
};

int Base::count = 0;

class Derived : public Base {
public:
    void increment() {
        count++;  // 派生类可以访问基类的静态成员
    }
};

 基类中的静态成员会被派生类共享。静态成员属于类,而不是某个具体对象,因此它们可以被派生类对象访问。

多继承

C++ 支持多继承,即一个类可以继承多个基类。然而,多继承可能引发一些问题,如命名冲突菱形继承问题(diamond inheritance problem)。

语法

class A {
public:
    void show() {
        std::cout << "Class A" << std::endl;
    }
};

class B {
public:
    void show() {
        std::cout << "Class B" << std::endl;
    }
};

class C : public A, public B {
public:
    void display() {
        A::show();  // 解决命名冲突  使用类域
        B::show();
    }
};

这篇继承就只是解释继承的最最最基本的语法或者与普通类不同的地方

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值