请教C++怎么用继承inheritance来代替模板template实现多态呢?

发布于 2022-09-06 01:01:34 字数 941 浏览 40 评论 0

今天面试的时候,遇到一个很简单的问题:继承和模板各自的优缺点。

我说:“模板的优点是可以把用同一算法用于不同类型数据,减少开发时间。模板的缺点是直到在编译时才能确定数据类型,所有用基于模板算法必须包含在整个设计的.h头文件中, 编译时间较长。……继承的优点是容易修改和扩展,缺点是打破封装,父类向子类暴露了实现细节,当父类的实现改变时可能要对子类做出相应的改变。” ——不知道我有没有说到点子上,欢迎补充!

面试官说:“能不能举一个例子,继承比模板更好呢?” 我想了半天,不知道该怎么回答……
面试官等了一会看我没反应,于是写了一个简单的模板:

template <typename T> class ttt
    {
    private:
        T x;
    public:
        T(T x); // 构造函数
    };
int main()
    ttt<int> t1(12345);
    ttt<float> t2(0.6789);

这可以认为是模板实现类数据类型的多态。他问我:怎么才能用继承来实现这个多态?

我想了一下,大概就是

class A
    {
    private:
        int x;
    public:
        A(): A(x)
    };
class B: public A
    {
    private:
        float y;
    ...
    };

但是感觉没法用继承把x变成y,没法在main里,让A的类内成员数据随心所欲的改变类型。难道可以直接在private里把变量虚化virtual吗?

所以请教一下:到底什么情况下继承比模板更好呢?这个数据类型的多态到底怎么用继承来实现呢?

谢谢了先!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

娇纵 2022-09-13 01:01:34

尝试回答讨论,有理解不对的地方请指正.

这可以认为是模板实现类数据类型的多态

我理解这不算做模板实现了多态. 而且面试官泛化了内置类型,有点误导你了.

模板:实现了对类型(STL)的泛化,本质上也是对类(自定义类)的泛化.
继承:实现了对自定义类的泛化

具体看代码

// static binding
/*
class Cat
{
public:
    static void say_hello() {
        std::cout<<"miao miao miao!"<<std::endl;
    }
};
class Dog
{
public:
    static void say_hello() {
        std::cout<<"wang wang wang!"<<std::endl;
    }
};
template<typename T>
class Pet
{
public:
   void say_hello() {
       T::say_hello();
   }
};
 */

// dynamic binding
class Pet1
{
public:
    virtual void say_hello() = 0;
};
class Cat1 : public Pet1
{
public:
    void say_hello(){
        std::cout<<"1 miao miao miao!"<<std::endl;
    }
};
class Dog1 : public Pet1
{
public:
    void say_hello(){
        std::cout<<"2 wang wang wang!"<<std::endl;
    }
};

int main() {
    /*
    Pet<Cat> cat;
    Pet<Dog> dog;
    cat.say_hello();
    dog.say_hello();
     */

    std::vector<Pet1 *> pets;
    pets.push_back(new Cat1);
    pets.push_back(new Dog1);
    for(auto p : pets) {
       p->say_hello();
    }

    return 0;
}

为什么说面试官给的例子可能误导你了呢,因为他对内置类型做了泛化(int/float),这些类型本身也不是通过继承来实现的.比如int和float都支持加法操作,但显然不是通过继承公共基类实现的.
所以我们用用户自定义的类型来区分模板继承的差异.

  • 模板类Pet,抽象了类CatDogsay_hello功能从而实现了泛化
  • Pet1作为抽象基类,也抽象了Cat1Dog1say_hello功能,这个是通过继承来实现的.

不太认同面试官所谓的多态,如果非要说多态,那也是静态的,多态应该是动态绑定比如伪码:

...
    std::vector<Pet1 *>pets;
    if(readFromConfigurationFile() == "Cat1") pets.push_back(new Cat1);
    else pets.push_back(new Dog1);

容器内指针实际指向的类型编译期无法确认,而是通过运行期(读配置文件/数据库...)才能确认,而这个能力模板是不具备的.

总结: 
模板就是用在编译期的,多态发生在运行期进行的动态绑定;这个就是本质的区别.
至于各自的优缺点,话题有点大. 从工程实践来看,模板更适合提供各类API(参见STL/BOOST接口), 继承更适合提供框架(参见ACE)

所以请教一下:到底什么情况下继承比模板更好呢?这个数据类型的多态到底怎么用继承来实现呢?

1.需要动态绑定的时候
2.面试官没有给出这个模板任何抽象出来的操作. 那完全可以这样

class NumberType
{
public:
    virtual ~NumberType() {
    }
};
class IntType : public NumberType
{
public:
    virtual ~IntType() {
    }
private:
    int x;
};
class FloatType: public NumberType
{
public:
    virtual ~FloatType() {
    }
private:
    float x;
};
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文