代码之家  ›  专栏  ›  技术社区  ›  Tyler Jackson

子类中变量函数特化的定义

  •  0
  • Tyler Jackson  · 技术社区  · 7 年前

    我试图允许一个子类定义变量函数专门化。例如:

    #include <iostream>
    #include <vector>
    #include <memory>
    
    class BaseClass
    {
    public:
        BaseClass() {};
        virtual ~BaseClass() {};
    
        template<typename GenericData>
        void ReceiveData(GenericData &inData)
        {
            throw std::runtime_error("Undefined");
        }
    };
    
    class ReceiveInt : public BaseClass
    {
        void ReceiveData(int & inData)
        {
            std::cout << "I know what to do!";
        }
    };
    
    
    int main(int argc, char* argv[])
    {
        std::vector<std::shared_ptr<BaseClass>> classHolder;
        classHolder.push_back(std::make_shared<ReceiveInt>());
    
        int test = 1;
        classHolder.front()->ReceiveData(test);
    
        return 0;
    }
    

    但不幸的是,这不起作用,因为调用了基类ReceiveData函数。这可能吗?

    编辑1 正如人们所指出的,我的记法大错特错。看来我今天学到的比我想象的要多。

    5 回复  |  直到 7 年前
        1
  •  2
  •   R Sahu    7 年前

    这可能吗?

    我不这么认为。

    动态调度只能用于 virtual 成员函数。

    成员函数模板不能 事实上的 .

    如果可以使用常规成员函数,即不使用成员函数模板,则可以制作它们 事实上的 . 那会有用的。

        2
  •  2
  •   Edgar Rokjān    7 年前

    你在这里混淆了一些概念。

    首先,这里没有变量模板 ReceiveData 功能如下:

    template<typename GenericData>
    void ReceiveData(GenericData &inData)
    {
        throw std::runtime_error("Undefined");
    }
    

    是模板成员函数。

    然后,如果要重写派生类中的方法,正确的方法是使用 事实上的 功能,可能是 纯虚拟的 基类中的函数和 事实上的 具有 推翻 派生类中的说明符。

    然而 virtual 函数将您限制为一组固定类型,因为没有模板虚拟函数。你可以用 CRTP 尽管:

    template<typename T>
    class Base {
    public:
        void receiveData(const T&) {}
    };
    
    class ReceiveInt : public Base<int> {};
    

    它模拟了一种静态多态性。以下内容:

    ReceiveInt{}.receiveData(int{});
    

    receiveData 从用实例化的基类 int .

        3
  •  1
  •   Austin Brunkhorst    7 年前

    我想你可能混淆了你的术语。 BaseClass::ReceiveData 是一个模板化方法,采用 模板参数 GenericData . 一个可变函数需要 论据 在运行时确定。

    在里面 ReceiveInt ,你没有对任何东西进行专门化,因为 ReceiveInt::ReceiveData 不是模板化方法。事实上,即使它是模板化的,也不可能调用您的示例。指针如何指向 BaseClass 知道如何在它指向的派生类中调用模板专门化吗?

    你可以 基类::ReceiveData virtual . 这允许您在基类中重写它,并仍然使用指向 基类 . 不幸的是,模板是一种编译时语言特性,而动态调度是一种运行时特性——在本文中,您不能同时拥有这两种特性。

    工具书类

        4
  •  1
  •   SoronelHaetir    7 年前

    您必须首先强制转换到派生类型,因为基类只知道自己的实现,所以不可能使用基类指针/引用。这甚至不是一种可以对派生类型使用递归依赖的情况,因为在实例化基时尚未定义派生类型。

    如果您对派生类型进行强制转换,那么它将能够根据需要解析派生成员。

        5
  •  0
  •   StPiere    7 年前

    代码中没有其他人已经解释过的可变模板。 但您可以利用这样一个事实,即模板化的类方法是在第一次调用时实例化的。但这里没有虚拟覆盖。 在本例中,您可以在基类和派生类中定义方法模板的不同实现,但您必须明确告诉编译器要使用哪一个。 如果没有显式强制转换,则无法通过基类指针使用派生类方法:

    #include <iostream>
    #include <memory>
    using namespace std;
    
    class Base
    {
    public:
        Base() {};
        virtual ~Base() {};
    
        template<typename T>
        void ReceiveData(T)
        {
            throw std::runtime_error("Undefined");
        }
    };
    
    class Derived : public Base
    {
    public:
        template<typename... Args >
        void ReceiveData(Args... args)
        {
            (void)std::initializer_list<int>{(std::cout << args << std::endl, 0)...};
        }
    };
    
    
    int main()
    {
        Base b;
        //  b.ReceiveData(1);       //-> this calls base class method
    
        Derived d;
        d.ReceiveData(1);           // this calls the method in the derived class
    
        d.ReceiveData(2, "hello");  // this calls the method in the derived class
    
        Base* b2 = new Derived();
        // b2->ReceiveData(3);      // this will instantiate and call the base class method
                                    // thus raising an exception
                                    // because no virtual overriding of templated methods
    
        ((Derived*)b2)->ReceiveData("world",1); // this will instantiate and call the derived class 
                                                // method, then because of explicit casting the 
                                                // compiler knows which class to target
    
        return 0;
    }
    

    现场演示: https://wandbox.org/permlink/K0qEAC7C7yzg6gYL