您好,欢迎来到刀刀网。
搜索
您的当前位置:首页如何实现接口继承与实现继承的区别?如何处理多态性与性能的平衡?

如何实现接口继承与实现继承的区别?如何处理多态性与性能的平衡?

来源:刀刀网

接口继承与实现继承的区别及实现方式

接口继承(纯虚函数)

在 C++ 中,接口继承主要通过纯虚函数来实现。纯虚函数是在基类中声明的虚函数,它在基类中没有定义,只提供了函数签名,其形式为virtual 返回类型 函数名(参数列表)=0;。例如:

class Shape {
public:
    virtual double area() = 0; 
    virtual double perimeter() = 0;
};
  - 这里的`Shape`类是一个抽象类,不能创建它的对象。它定义了两个纯虚函数`area`和`perimeter`,这两个函数相当于接口。任何继承自`Shape`类的派生类都必须实现这两个函数,否则派生类也会成为抽象类。例如,`Rectangle`类继承自`Shape`类:
     ```cpp
     class Rectangle : public Shape {
     private:
         double length;
         double width;
     public:
         Rectangle(double l, double w) : length(l), width(w) {}
         double area() override {
             return length * width;
         }
         double perimeter() override {
             return 2 * (length + width);
         }
     };

这种继承方式强制派生类遵循基类定义的接口规范,主要用于实现多态性,即通过基类指针或引用调用派生类的函数

实现继承(非纯虚函数)

实现继承是指派生类继承基类的函数实现。当基类中的函数不是纯虚函数时,派生类可以选择继承基类的函数实现,也可以重写(覆盖)它。例如:

class Animal {
public:
    void move() {
        std::cout << "Animal moves." << std::endl;
    }
};
class Dog : public Animal {
public:
    void move() override {
        std::cout << "Dog runs." << std::endl;
    }
};
- 在这个例子中,`Animal`类有一个非纯虚函数`move`。`Dog`类继承自`Animal`类,并且重写了`move`函数。如果`Dog`类没有重写`move`函数,那么当通过`Dog`类对象调用`move`函数时,会调用`Animal`类中的`move`函数实现。
2. **多态性与性能的平衡**
   - **多态性的代价**
     - 多态性主要通过虚函数来实现。当使用虚函数时,C++会在对象的内存布局中添加一个虚函数表(v - table)指针。每次通过基类指针或引用调用虚函数时,需要通过虚函数表来查找真正要调用的函数地址,这会带来一定的运行时开销。例如:
     ```cpp
     Shape* shapePtr;
     Rectangle rect(3, 4);
     shapePtr = &rect;
     shapePtr->area();

性能优化策略

避免不必要的虚函数调用:

如果在某些特定场景下,你确定对象的实际类型,并且不需要多态行为,可以直接通过对象本身来调用函数,而不是通过基类指针或引用。例如:

Rectangle rect(3, 4);
rect.area(); 
- 这种方式避免了虚函数调用的开销。
     - **内联虚函数(有条件使用)**:对于一些简单的虚函数,并且在性能敏感的代码中,可以考虑将其声明为内联函数。不过需要注意的是,编译器是否真正内联函数还要看函数的复杂程度等因素。例如:
     ```cpp
     class Shape {
     public:
         virtual inline double area() = 0; 
     };

但是,对于复杂的多态层次结构和频繁调用的虚函数,内联可能不会起到很好的效果,因为虚函数的多态性本质上还是需要运行时的动态分派。

使用非虚接口(NVI)模式:这种模式将公共接口定义为非虚函数,在非虚函数内部调用虚函数来完成实际的工作。例如:

class Shape {
public:
    double calculateArea() {
        return doArea();
    }
private:
    virtual double doArea() = 0;
};

这样,在calculateArea函数中可以进行一些预处理或者后处理工作,同时通过doArea虚函数保持多态性。并且,对于一些不需要多态的情况,可以直接调用calculateArea函数,减少虚函数调用的开销。

因篇幅问题不能全部显示,请点此查看更多更全内容

Copyright © 2019- gamedaodao.com 版权所有 湘ICP备2022005869号-6

违法及侵权请联系:TEL:199 18 7713 E-MAIL:2724546146@qq.com

本站由北京市万商天勤律师事务所王兴未律师提供法律服务