马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。
您需要 登录 才可以下载或查看,没有账号?立即注册
×
目次
接口的通用界说
特点:
C++ 中的接口
接口的作用
接口与抽象类的区别
什么是多态?
多态的范例
1. 编译时多态
2. 运行时多态
多态的实现原理
留意事项
在编程中,接口(Interface) 是一个抽象概念,用于界说一组举动规范或功能约定,而不提供具体实现。它是一种左券,规定了实现它的类必须提供哪些方法或功能。接口广泛用于面向对象编程(OOP)中,以实现模块化、解耦和多态。
下面我会从通用概念和 C++ 的角度具体表明“接口”。
接口的通用界说
接口可以看作是类与类之间通讯的桥梁。它只声明方法(或函数)的署名(如名称、参数、返回值范例),而不关心这些方法怎样实现。实现接口的类必须按照接口的界说提供具体实现。
特点:
- 抽象性:接口自己不包罗实现细节。
- 欺压性:实现接口的类必须实现全部接口中界说的方法。
- 多态性:通过接口范例引用具体实现,可以在运行时动态调用差异类的举动。
比喻:接口就像一份条约,规定了“做什么”(what),但不关心“怎么做”(how)。比如,一个“电源插座”接口界说了“提供220V交换电”的规范,具体是水力发电照旧太阳能发电由实现者决定。
C++ 中的接口
C++ 没有像 Java 或 C# 那样的显式 interface 关键字,但通过纯虚函数和抽象类,可以实现接口的功能。具体来说:
- 一个类中全部函数都是纯虚函数(virtual ... = 0)的抽象类,通常被用作接口。
- 派生类继承这个抽象类并实现全部纯虚函数。
示例:C++ 中的接口
- #include <iostream>
- using namespace std;
- // 接口(抽象基类)
- class Printable {
- public:
- virtual void print() const = 0; // 纯虚函数
- virtual ~Printable() {} // 虚析构函数,确保正确清理
- };
- // 实现接口的类
- class Book : public Printable {
- private:
- string title;
- public:
- Book(const string& t) : title(t) {}
- void print() const override {
- cout << "Book: " << title << endl;
- }
- };
- class Article : public Printable {
- private:
- string author;
- public:
- Article(const string& a) : author(a) {}
- void print() const override {
- cout << "Article by: " << author << endl;
- }
- };
- int main() {
- Printable* items[2];
- items[0] = new Book("C++ Primer");
- items[1] = new Article("John Doe");
- for (int i = 0; i < 2; i++) {
- items[i]->print(); // 多态调用
- delete items[i];
- }
- return 0;
- }
复制代码 输出:
- Book: C++ Primer
- Article by: John Doe
复制代码 在这个例子中:
- Printable 是一个接口,界说了 print 方法。
- Book 和 Article 是具体类,实现了 Printable 接口。
- 通过 Printable* 指针,可以同一调用差异类的 print 方法,实现多态。
接口的作用
- 解耦合:
调用方只依赖接口,不依赖具体实现。比方,main 函数不必要知道 Book 或 Article 的细节,只需知道它们实现了 Printable。
- 可扩展性:
新增一个实现类(如 Magazine)时,无需修改现有代码,只要它实现 Printable 接口即可。
- 多态性:
通过基类指针或引用调用派生类的实现,动态绑定到精确的函数。
- 规范化:
欺压全部实现类提供划一的举动(如 print 方法)。
接口与抽象类的区别
在 C++ 中,接口和抽象类都依赖纯虚函数,但它们有渺小区别:
- 接口:通常只包罗纯虚函数,纯粹界说举动规范,没有数据成员或实现。
- 抽象类:可以包罗纯虚函数、平常虚函数乃至具体实现,大概尚有数据成员,用于提供部门默认举动。
示例(抽象类 vs 接口):
- // 接口
- class ILog {
- public:
- virtual void log(const string& message) = 0;
- virtual ~ILog() {}
- };
- // 抽象类
- class Logger {
- protected:
- string prefix;
- public:
- Logger(const string& p) : prefix(p) {}
- virtual void log(const string& message) = 0; // 纯虚函数
- void info(const string& msg) { // 提供默认实现
- log(prefix + " INFO: " + msg);
- }
- };
复制代码
什么是多态?
多态,字面意思是“多种形态”,在编程中指的是同一个接口或方法可以在差异的对象上表现出差异的举动。换句话说,多态允许用同一的接口调用差异类的实现,而具体实验哪个实现取决于对象的现实范例。
平常表明:多态就像一个遥控器,按下“播放”按钮,差异装备(电视、音响、DVD播放器)会有差异的反应,但你只必要知道“按播放”就行,不消管背后是哪种装备。
多态的范例
在 C++ 中,多态紧张分为两种:
- 编译时多态(Compile-time Polymorphism)
- 通过**函数重载(Function Overloading)和运算符重载(Operator Overloading)**实现。
- 在编译时就确定调用哪个函数。
- 运行时多态(Run-time Polymorphism)
- 通过**虚函数(Virtual Function)**和继承实现。
- 在运行时根据对象的现实范例动态决定调用哪个函数。
1. 编译时多态
编译时多态是静态的,依赖函数名雷同但参数差异的重载机制。
示例:函数重载
- #include <iostream>
- using namespace std;
- class Calculator {
- public:
- int add(int a, int b) {
- return a + b;
- }
- double add(double a, double b) {
- return a + b;
- }
- };
- int main() {
- Calculator calc;
- cout << calc.add(2, 3) << endl; // 调用 int 版本,输出 5
- cout << calc.add(2.5, 3.7) << endl; // 调用 double 版本,输出 6.2
- return 0;
- }
复制代码 这里 add 函数根据参数范例在编译时选择符合的版本。
示例:运算符重载
- class Complex {
- private:
- double real, imag;
- public:
- Complex(double r, double i) : real(r), imag(i) {}
- Complex operator+(const Complex& other) {
- return Complex(real + other.real, imag + other.imag);
- }
- void print() {
- cout << real << " + " << imag << "i" << endl;
- }
- };
- int main() {
- Complex a(1.0, 2.0), b(3.0, 4.0);
- Complex c = a + b; // 重载了 + 运算符
- c.print(); // 输出 4 + 6i
- return 0;
- }
复制代码 + 运算符被重载,编译器根据上下文选择实现。
2. 运行时多态
运行时多态是动态的,依赖继承和虚函数机制。通过基类指针或引用调用派生类的函数,具体调用哪个版本在运行时决定。
示例:虚函数实现多态
- #include <iostream>
- using namespace std;
- class Animal {
- public:
- virtual void sound() { // 虚函数
- cout << "Some generic animal sound" << endl;
- }
- virtual ~Animal() {} // 虚析构函数
- };
- class Dog : public Animal {
- public:
- void sound() override {
- cout << "Woof" << endl;
- }
- };
- class Cat : public Animal {
- public:
- void sound() override {
- cout << "Meow" << endl;
- }
- };
- int main() {
- Animal* animals[2];
- animals[0] = new Dog();
- animals[1] = new Cat();
- for (int i = 0; i < 2; i++) {
- animals[i]->sound(); // 运行时根据对象类型调用
- delete animals[i];
- }
- return 0;
- }
复制代码 输出:
- Animal* 指针指向 Dog 或 Cat 对象,调用 sound() 时根据现实对象范例实验对应版本。
- 这是运行时多态的核心,依赖虚函数表(vtable)实现。
没有虚函数的对比
假如去掉 virtual:
- class Animal {
- public:
- void sound() {
- cout << "Some generic animal sound" << endl;
- }
- };
- class Dog : public Animal {
- public:
- void sound() {
- cout << "Woof" << endl;
- }
- };
- int main() {
- Animal* ptr = new Dog();
- ptr->sound(); // 输出 "Some generic animal sound"
- delete ptr;
- return 0;
- }
复制代码 没有 virtual,调用的是 Animal 的版本,由于指针范例是 Animal*,这就是静态绑定。
多态的实现原理
运行时多态依赖虚函数表(vtable):
- 每个包罗虚函数的类有一个虚函数表,存储虚函数的所在。
- 每个对象包罗一个指向其类虚函数表的指针(vptr)。
- 调用虚函数时,通过 vptr 查找表中的函数所在,动态调用。
过程:
- 编译器在类中插入 vptr。
- 对象创建时,vptr 被初始化为指向对应类的 vtable。
- 调用虚函数时,步调通过 vptr 找到并实验精确的函数。
留意事项
- 性能开销:运行时多态通过 vtable 实现,有少量内存和间接调用的开销。
- 虚函数要求:必须通过指针或引用调用,对象直接调用还是静态绑定。
- 虚析构函数:基类应有虚析构函数,克制删除派生类对象时资源走漏。
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
|