✨博客主页 | ||
---|---|---|
何曾参静谧的博客 | ||
📌文章专栏 | ||
「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 <iostream>
#include <cstring> // 基类
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++的面向对象编程至关重要。通过合理地使用继承机制,我们可以创建更加灵活和可扩展的代码结构。