C ++ пользовательский гетерогенный контейнер с помощью полиморфизма и указателей - PullRequest
0 голосов
/ 29 марта 2012

Я пишу очень простую и маленькую оболочку для sqlite3 и использую sqlite3_get_table (), чтобы получить результаты как char**.Я использую базовый класс данных, чтобы иметь возможность хранить поля в едином контейнере, а именно записывать здесь, а затем извлекать каждый тип данных, в частности, используя производные типы.

Это мой базовый класс:

class data
{
    private:
        uint sz;
        virtual void abstract() = 0;

    public:
        inline data(char* pd);
        inline data();
        uint size() {return sz;}
};

и вот пример производного класса:

class str : public data
{
    private:
        string* pdata;
        virtual void abstract() {}

    public:
        inline str(char* pd);
        inline operator string();
        inline operator const char*();
};

и класс записи:

class record
{
    private:
        ushort cols;
        data** entries;
    public:
        record(char** ppdata, uint col_count);
        inline data* operator [](ushort field);
        inline uint num_fields() {return cols;}
};

record operator[] (inline data* operator [](ushort field);) позволяет мнеполучить доступ к базовому классу data следующим образом:

db::str* mys = dynamic_cast<db::str*>((*record)[3]);

и скомпилировать: g++ -o main -lsqlite3 main.cpp в Arch Linux, и при компиляции проблем нет.Но когда я запускаю его, я получаю Segmentation Fault.

Комментирование строки dynamic_cast делает меня счастливым, но я лично думаю, что я каким-то образом ошибаюсь в унынии, а не думаю, что есть проблема с определением или использованиемиз класса data.

Я также ценю любые радикальные оскорбления в моем коде, так как я знаю, что я новичок.Большое спасибо.

Ответы [ 3 ]

1 голос
/ 29 марта 2012

Вы не делаете downcast, вы делаете upcast.Класс data - это база, возвращаемая operator[], и вы приводите его к db::str*, который является дочерним.Не каждый data является str, поэтому для начала вам следует проверить, является ли то, что вы пытаетесь разыграть, str и не возвращает ли приведение 0. 0. 1009 *

Кроме того,Вы должны привыкнуть к использованию Valgrind , в частности, его инструмента memcheck .Вы могли бы точно определить место и причину в считанные секунды, и как сам пользователь Arch, я гарантирую вам, что это в репозиториях.Вы запускаете свою программу с valgrind --tool=memcheck ./myprogram.

1 голос
/ 31 марта 2012

Спасибо вам обоим, TC1 и Марку Рэнсому. Я попытался изменить свою проблему, и, наконец, понял, что это лучшее решение, сравнивая его преимущества с его компромиссами, для простой обертки, подобной той, которую я пишу (sqlite3's sqlite3_get_table()):

enum types {INT, FLOAT, STRING, BLOB, NUL};

class bad_type {};

class data
{
    private:
        void* pdata;
        types type;

    public:
        data(int dt)
        {
            int* tmp = new int(dt);
            pdata = static_cast<void*>(tmp);
            type = INT;
        }
        // constructors for other types to be added in a similar fashion.

        operator int()
        {
            if (type == INT)
                return *(static_cast<int*>(pdata));
            throw bad_type();
        }
        // operators for other types to be added in a similar fashion.
};

Таким образом, я делаю данные * очень подходящим типом указателя для создания гетерогенного контейнера (извините, что я не знал слова, когда задавал вопрос ;-)) в таком случае, когда типы данных ограничены , 5 в этом случае, так как он работает на каком-то низком уровне.

Я просто использовал его в своем тесте main, как это:

data* array[3];
array[0] = new data(3);

cout << *(array[0]);

И это действительно дает мне 3, и, безусловно, должна быть возможность применить его и к любому другому типу, особенно на низком уровне в этом случае, когда типы часто являются фундаментальными, а не сложными унаследованными.

Я пришел к выводу, что в таких случаях static_cast можно терпеть, пожалуйста, поправьте меня, если я ошибаюсь. А также я действительно хочу узнать как ваши критические замечания, так и оценки этого решения, поскольку оно помогает мне учиться как новичку.

Спасибо.

1 голос
/ 29 марта 2012

Когда вы используете dynamic_cast, вам нужно проверить результат, чтобы увидеть, если это NULL. Это происходит, когда объект на самом деле не является экземпляром того типа, к которому вы пытались привести.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...