C++ 中基于模板和多态性的方法有何优缺点?

问题描述 投票:0回答:1

我编写了一个程序,其中变量的类型在编译时未知。在运行时向用户询问。在第一个程序版本中,重复了部分代码。修改涉及所使用的变量类型。在第二和第三个程序版本中,使用了基于模板的方法和基于多态性的方法(具有抽象类和虚函数)。
所有程序都运行良好。但我想知道这两种方法的优缺点是什么,什么时候一种方法比另一种方法最合适,以及是否存在另一种方法?

为了澄清我的问题,下面是一个例子:
第一个版本(有代码重复)

#include <iostream>
using namespace std;

class Shape {
    public : float lgth;
    public : void getLgth() { cin >> lgth;}
};

class Square : public Shape {
    public : float calcArea() { return lgth * lgth; }
};

class Circle : public Shape {
    public : float calcArea() { return 3.14 * lgth * lgth; }
};

int main() {
    char shape_type;

    cout <<"Shape Type (c/s) ? ";
    cin >> shape_type;
    if (shape_type == 'c') {
      Circle my_shape;
      cout << "Shape Length ? ";
      my_shape.getLgth();
      cout << "Shape Area : " << my_shape.calcArea() << endl;
    }
    else if (shape_type == 's') {
      Square my_shape;
      // --- Code repetition ---
      cout << "Shape Length ? ";
      my_shape.getLgth();
      cout << "Shape Area : " << my_shape.calcArea() << endl;
    }

    return 0;
}

基于模板的方法
添加模板

template <typename TShape>
// requires(std::derived_from<TShape, Shape>) // C++20 constraint
void do_job()
{
    TShape my_shape;
    std::cout << "Shape Length ?";
    my_shape.getLgth();
    std::cout << "Shape Area : " << my_shape.calcArea() << std::endl;
}

主要修改如下

if (shape_type == 'c') {
    do_job<Circle>();
} else if (shape_type == 's') {
    do_job<Square>();
}

基于多态性的方法

#include <iostream>
using namespace std;

// abstract class : Shape
// virtual function : calcArea
class Shape {
    public :
        float lgth;
        virtual ~Shape() = default;
        void getLgth() { cin >> lgth; }
        virtual float calcArea() = 0;
};

class Square : public Shape {
    public :
        float calcArea() override { return lgth * lgth; }
};

class Circle : public Shape {
    public :
        float calcArea() override { return 3.14 * lgth * lgth; }
};

int main() {
    char shape_type;
    Shape* my_shape;

    cout << "Shape Type (c/s) ? ";
    cin >> shape_type;

    if (shape_type == 'c') {
        my_shape = new Circle;
    }
    else if (shape_type == 's') {
        my_shape = new Square;
    }
    else {
        cout << "Unknown type!" << endl;
        return -1;
    }

    cout << "Shape Length ? ";
    my_shape->getLgth();
    cout << "Shape Area : " << my_shape->calcArea() << endl;

    delete my_shape;

    return 0;
}
c++ oop templates polymorphism
1个回答
0
投票

没有任何优点和缺点。模板和继承是解决不同问题的不同机制。有时,您可以在其中一种更合适时强制使用另一种,特别是在非常简单的示例中,您最终只对对象做一件事,但一般来说,最好使用模板,其中模板是合适的解决方案,而继承是继承是合适的解决方案。

从或多或少的理论角度来看:模板为不同的接口提供了通用的实现,继承为通用的接口提供了不同的实现。例如,在标准中,

std::vector
是一个模板:例如,
std::vector<double>
提供函数
push_back( double )
,而
std::vector<int>
提供
push_back( int )
。但这两个函数具有相同的实现。另一方面,尽管
std::ostream
std::ofstream
的输出字符(实现)完全不同,但
std::ostringstream
的接口完全相同。

另一个重要的区别是模板在编译时解析,而虚函数在运行时解析。这意味着调用函数模板(或类模板的成员函数)通常会更快(但这可能会因需要额外的代码来显式选择要调用的函数而被抵消),并且可能有更多的可能性编译器来分析正在发生的事情,以便更好地进行错误检查或优化。另一方面,这意味着任何调用点只能调用该函数的一个特定实例;如果您有多个调用站点并希望在每个调用站点调用不同的函数,则模板要求您在每个调用站点显式确定类型,并为每个不同的函数提供单独的函数调用。

© www.soinside.com 2019 - 2024. All rights reserved.