「C/C++」C++ 三大特性 之 继承

在这里插入图片描述

✨博客主页
何曾参静谧的博客
文章专栏
「C/C++」C/C++程序设计
全部专栏
「VS」Visual Studio 「C/C++」C/C++程序设计 「UG/NX」BlockUI集合
「Win」Windows程序设计 「DSA」数据结构与算法 「UG/NX」NX二次开发
「QT」QT5程序设计 「File」数据文件格式 「PK」Parasolid函数说明

目录

    • C++ 继承中的函数详解
      • 1. 函数的继承
      • 2. 函数的重写(覆盖)
      • 3. 函数的隐藏
      • 4. 多态性
      • 5. 函数访问权限的变化
      • 6. 详细示例
      • 总结

C++ 继承中的函数详解

在C++面向对象编程中,继承是一种强大的机制,它允许我们创建一个新的类(派生类)来继承另一个类(基类)的属性和方法。这种机制促进了代码的重用和扩展性。在继承关系中,基类的成员函数在派生类中仍然有效,并且可以根据需要进行重写或扩展。本文将详细探讨C++继承中的函数,包括函数的继承、重写(覆盖)、隐藏、多态性以及函数访问权限的变化。

1. 函数的继承

当派生类从基类继承时,基类的公有成员函数和保护成员函数会自动成为派生类的成员。这些成员在派生类中具有与在基类中相同的访问权限(除非在派生类中被进一步限制)。

class Base {
public:
    void publicFunc() { /* ... */ }
protected:
    void protectedFunc() { /* ... */ }
};

class Derived : public Base {
    // Base::publicFunc() 和 Base::protectedFunc() 都是 Derived 的成员
};

在上面的例子中,Derived 类继承了 Base 类的 publicFunc()protectedFunc() 成员函数。publicFunc()Derived 类中仍然是公有的,而 protectedFunc()Derived 类中保持保护状态。

2. 函数的重写(覆盖)

重写(也称为覆盖)是指在派生类中重新定义基类中已经存在的虚函数。要重写一个函数,派生类中的函数必须具有与基类中的虚函数相同的名称、返回类型和参数列表。

class Base {
public:
    virtual void virtualFunc() { /* 基类实现 */ }
};

class Derived : public Base {
public:
    // 重写基类的虚函数
    void virtualFunc() override { /* 派生类实现 */ }
};

在上面的例子中,Derived 类重写了 Base 类的 virtualFunc() 成员函数。override 关键字是C++11引入的,它用于明确指出一个函数是重写基类中的虚函数,如果重写不正确,编译器会报错。

3. 函数的隐藏

与重写不同,如果派生类定义了一个与基类中的非虚函数同名的函数(即使参数列表不同),那么基类的该函数在派生类作用域内将被隐藏。这意味着通过派生类对象或指针无法访问基类的同名函数。

class Base {
public:
    void func() { /* 基类实现 */ }
};

class Derived : public Base {
public:
    // 隐藏基类的 func() 函数
    void func(int) { /* 派生类实现 */ }
};

int main() {
    Derived d;
    d.func(1); // 调用 Derived::func(int)
    // d.func(); // 错误:无法访问隐藏的 Base::func()
    Base* b = &d;
    b->func(); // 调用 Base::func(),因为 b 是基类指针
    return 0;
}

在上面的例子中,Derived 类定义了一个与 Base 类中的 func() 同名的函数,但参数列表不同。这导致 Base 类的 func() 函数在 Derived 类作用域内被隐藏。

4. 多态性

多态性是面向对象编程的一个重要特性,它允许我们通过基类指针或引用来调用派生类中的重写函数。要实现多态性,基类中的函数必须是虚函数。

class Base {
public:
    virtual void show() { std::cout << "Base show" << std::endl; }
    virtual ~Base() = default; // 虚析构函数,确保正确调用派生类的析构函数
};

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

int main() {
    Base* b1 = new Base();
    Base* b2 = new Derived(); // 基类指针指向派生类对象

    b1->show(); // 调用 Base::show()
    b2->show(); // 调用 Derived::show(),体现多态性

    delete b1;
    delete b2;
    return 0;
}

在上面的例子中,b2 是一个基类指针,但它指向一个 Derived 对象。当我们调用 b2->show() 时,实际上调用的是 Derived 类中的 show() 函数,这就是多态性的体现。

5. 函数访问权限的变化

在继承中,基类的成员函数在派生类中的访问权限可能会发生变化。如果基类中的函数是公有的,那么在派生类中它仍然是公有的(除非在派生类中被进一步限制)。如果基类中的函数是保护的或私有的,那么在派生类中它仍然保持相应的访问权限。

然而,需要注意的是,即使基类中的函数是保护的或私有的,派生类仍然可以通过基类指针或引用来调用这些函数(如果它们是虚函数并被重写)。这是因为虚函数调用是在运行时解析的,而不是在编译时。

class Base {
protected:
    void protectedFunc() { /* ... */ }
private:
    void privateFunc() { /* ... */ }
public:
    virtual void virtualFunc() { /* 基类实现 */ }
};

class Derived : public Base {
public:
    // 无法直接访问 Base::privateFunc(),因为它在基类中是私有的
    // 但可以重写 Base::virtualFunc()
    void virtualFunc() override { /* 派生类实现 */ }

    // 可以访问 Base::protectedFunc(),因为它在基类中是保护的
    void callProtectedFunc() {
        protectedFunc(); // 合法
        // privateFunc(); // 错误:无法访问基类的私有成员函数
    }
};

6. 详细示例

#include   
#include   
  
// 基类  
class Base {  
private:  
    char* data;  
  
public:  
    // 基类的构造函数,用于分配内存  
    Base(const char* str = "") {  
        data = new char[strlen(str) + 1];  
        strcpy(data, str);  
        std::cout << "Base constructor called, data: " << data << std::endl;  
    }  
  
    // 基类的虚析构函数,确保正确调用派生类的析构函数  
    virtual ~Base() {  
        std::cout << "Base destructor called, deleting data: " << data << std::endl;  
        delete[] data;  
    }  
  
    // 基类的虚函数,用于演示多态性  
    virtual void show() {  
        std::cout << "Base show, data: " << data << std::endl;  
    }  
};  
  
// 派生类  
class Derived : public Base {  
private:  
    int value;  
  
public:  
    // 派生类的构造函数,调用基类的构造函数并初始化自己的成员  
    Derived(int val, const char* str = "") : Base(str), value(val) {  
        std::cout << "Derived constructor called, value: " << value << std::endl;  
    }  
  
    // 派生类的析构函数,确保在基类析构函数之后调用  
    ~Derived() {  
        std::cout << "Derived destructor called, value: " << value << std::endl;  
    }  
  
    // 重写基类的虚函数  
    void show() override {  
        std::cout << "Derived show, value: " << value << ", data: " << Base::data << std::endl;  
    }  
};  
  
int main() {  
    // 创建派生类对象,并调用构造函数和析构函数  
    Derived d(42, "Hello from Derived");  
    d.show(); // 调用派生类的 show() 函数  
  
    // 通过基类指针创建派生类对象,并调用构造函数和析构函数  
    Base* b = new Derived(100, "Hello from Base pointer to Derived");  
    b->show(); // 调用派生类的 show() 函数,体现多态性  
  
    // 释放内存  
    delete b; // 先调用派生类的析构函数,然后调用基类的析构函数  
  
    // 注意:main 函数结束时,d 对象会自动调用其析构函数  
    return 0;  
}

总结

C++ 继承中的函数涉及多个方面,包括函数的继承、重写(覆盖)、隐藏、多态性以及函数访问权限的变化。理解这些概念对于深入掌握C++的面向对象编程至关重要。通过合理地使用继承机制,我们可以创建更加灵活和可扩展的代码结构。


在这里插入图片描述

你可能感兴趣的:(c语言,c++,开发语言)