• Восходящее преобразование массива производного класса к родительскому?

    @Mercury13
    Программист на «си с крестами» и не только
    Почему нельзя: если мы объявим ящик бананов ящиком фруктов и положим туда яблоко, он перестанет быть ящиком бананов.
    #include <iostream>
    
    class Vocal {  // интерфейс
    public:
        virtual void shout() = 0;
        virtual ~Vocal() = default;
    };
    
    class Dog : public Vocal {
    public:
        virtual void shout() override { std::cout << "Woof!" << std::endl; }
    };
    
    class Unrelated {};
    
    // ВАРИАНТ 1. Метод выкручивания рук.
    
    void shoutAll_v1(Vocal** x, int n)
    {
        for (int i = 0; i < n; ++i)
            x[i]->shout();
    }
    
    template <class T, int N>
    inline void shoutAll_v1(T* (&x)[N]) {
        // Тупая проверка концепции, ждём Си++20
        static_assert (std::is_base_of<Vocal, T>(), "Need array of Vocal");
        T** xx = x;
        shoutAll_v1(reinterpret_cast<Vocal**>(xx), N);
    }
    
    // ВАРИАНТ 2. Виртуальный полиморфизм.
    
    class Choir { // интерфейс
    public:
        virtual int size() const = 0;
        virtual Vocal& at(size_t i) const = 0;
        virtual ~Choir() = default;
    };
    
    void shoutAll_v2(const Choir& x)
    {
        int sz = x.size();
        for (int i = 0; i <sz; ++i)
            x.at(i).shout();
    }
    
    template <class T>
    class VocalArray : public Choir {
    public:
        template <int N>
        VocalArray(T* (&x)[N]) : fData(x), fSize(N) {}
        int size() const override { return fSize; }
        Vocal& at(size_t i) const override { return *fData[i]; }
    private:
        T** const fData;
        int fSize;
    };
    
    int main()
    {
        Dog* sons[3];
        for(auto& x : sons) {
            x = new Dog;
        }
        //Unrelated* unrel[3];
    
        std::cout << "V1" << std::endl;
        shoutAll_v1(sons);
        //shoutAll_v1(unrel);   не компилируется
    
        std::cout << "V2" << std::endl;
        shoutAll_v2(VocalArray<Dog>(sons));
        //shoutAll_v2(VocalArray<Unrelated>(unrel));  не компилируется
    
        return 0;
    }
    Ответ написан
    4 комментария