多态性和覆盖 C++ 中 class 模板的方法

Polymorphism and overriding a method from a class template in C++

我想要一个 class 模板,其中包含我的方法的基本实现,以及一组子 class 使用模板 class 和特定类型(双精度, int, char*) 并根据需要覆盖这些基本实现的某些子集。但是,除非我将对象声明为 subclass 的实例,否则我重写的方法似乎不会被调用。在探索这个问题时,我想出了以下代码:

#include <iostream>

template <typename T>
class BaseClass {
public:
    virtual void print1 (T thing) {
        std::cout << "Base print1: " << thing << std::endl;
    }

    virtual void print2 (T thing) {
        std::cout << "Base print2: " << thing << std::endl;
    }
};

class IntClass : public BaseClass<int> {
public:
    void print2 (int thing) {
        std::cout << "Int print2: " << thing << std::endl;
    }
};

int main()
{
    BaseClass<int> thing = IntClass();
    thing.print1(1);
    thing.print2(1);

    IntClass thing2 = IntClass();
    thing2.print1(2);
    thing2.print2(2);

    return 0;
}

我的预期输出是:

Base print1: 1
Int print2: 1
Base print1: 2
Int print2: 2

但相反,我得到:

Base print1: 1
Base print2: 1
Base print1: 2
Int print2: 2

是否可以在这里实现我的目标,或者在这种情况下,我最好为每种类型创建单独的基础 classes 吗?如果我的术语有点偏离,我深表歉意 - 我是 C++ 的新手。

thing的类型是BaseClass<int>,不是IntClass。在复制 BaseClass 子对象后,用于初始化它的临时 IntClass 已被销毁。像这样复制对象的一部分有时称为 切片

当您使用指向基 class 的引用或指针时,多态性起作用,它可能引用派生 class 的对象。因此,您将通过引用 IntClass 对象获得预期结果:

// In C++11 or later, you can bind an rvalue reference to a temporary, extending its lifetime
BaseClass<int> && thing = IntClass();

// If you're stuck in the past, you can bind an lvalue reference to a variable
IntClass ic;
BaseClass<int> & thing = ic;

BaseClass<int> thing = IntClass();

这与您认为的不同。它创建了 IntClass 的临时实例,然后将其复制到类型为 BaseClass<int>thing 中。结果称为对象切片(您可以搜索它)。

在这种情况下,由于派生类型在编译时已知,因此没有理由不使用 IntClass 作为 thing 的类型。但是对于一般用途,您需要使用指针。这是一个例子:

std::unique_ptr<BaseClass<int>> thing(new IntClass);
thing->print1(1);

如果你使用指针,你会达到你预期的结果。但是,正如我对这个答案的简短研究所了解的那样,这里发生的是 'thing' —— 称为 thing 的对象;不是参数,取 IntClass 的一部分,即 BaseClass 的一部分,并简单地丢弃其余部分。这称为对象切片。