2013-11-11 2 views
2

Что было бы лучшим способом реализовать список указателей на разные типы в C++?Список указателей на различные типы объектов

Я думал, что делать что-то вроде этого:

enum MyType {...}; 
typedef std::pair<MyType, void*> Ptr; 
std::vector <Ptr> list; 

А затем делать подходящее статическое приведение типа, как только мне нужно получить доступ к одному из объектов в списке.

Другой подход был бы имеющим различные векторы для каждого типа объекта:

std::vector<ClassA*> list_a; 
std::vector<ClassB*> list_b; 
... 

Вопрос заключается в том, что мне нужно реализовать график, где не все вершины имеют один и тот же тип.

EDIT. Производительность имеет решающее значение. Чем эффективнее код, тем лучше.

+2

Там всегда 'повышение :: variant'. – chris

ответ

6

Ваше лучшее решение будет состоять в том, чтобы все классы наследовали от одного и того же класса и указатели хранилища в базовый класс в списке. Используйте только void* как последнее и очень, очень опасное решение.

+0

Как преобразовать из базового класса в производный класс? С dynamic_cast? Какое-либо влияние на производительность? Я забыл упомянуть, что производительность критическая, и код должен быть очень эффективным. Спасибо – jbgs

+1

Да, для преобразования из указателя в базовый класс вам нужно использовать 'dynamic_cast'. другое решение состоит в том, чтобы базовый класс определял общий интерфейс, который будет реализован всеми дочерними классами, и тогда никакая броска не понадобится. –

+0

Ну, мне нужно 'dynamic_cast'.Общий интерфейс - это требование, которое трудно удовлетворить в этом случае. Но меня беспокоят штрафы за производительность ... – jbgs

2

Имейте все различные типы вершин, наследуемых от базового класса Vertex, затем используйте список Vertex*.

3

Я бы предпочел определить общий суперкласс для всех узлов вашего графика, например.

class Node { 
    // probably some fields giving siblings, or at least a unique number 
}; 

class GreenNode : public Node { 
    // etc... 
}; 

class YellowNode : public Node { 
}; 

class BlackLeaf : public Node { 
}; 
1

Как уже упоминалось, лучше использовать базовый класс + его потомков. Но если вы действительно хотите использовать C-структуры для узлов, тогда вы можете использовать общий подход «C» -style - поставить в начале каждой структуры какое-либо поле (пусть это будет int field), чтобы описать тип узла. Это поможет вам выяснить, какой тип каждый узел имеет:

typedef enum { 
    SMALL_NODE = 1, 
    NORML_NODE, 
    HUUGE_NODE, 
} type; 

struct small_node { 
    unsigned int type; /* type above - SMALL_NODE */ 
    /* ... */ 
}; 

struct norml_node { 
    unsigned int type; /* type above - NORML_NODE */ 
    /* ... */ 
}; 

struct huuge_node { 
    unsigned int type; /* type above - HUUGE_NODE */ 
    /* ... */ 
}; 
1

Есть три варианта в зависимости от ваших критериев:

  1. Используйте пустоту * указатель: это явно рассказывать любой читатель вашего код "удаляется". Это относится ко всем случаям, но вы полностью уверены, что информация о типе будет восстановлена ​​в другом месте, где это будет необходимо.

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

    struct ListInterface { // struct for defaulting to public 
        void Poke(uint addr, uint value) = 0; 
        uint Poke(uint addr) const = 0; 
    }; 
    
    class SplineVertex : public Vertex, public ListInterface { 
        ... 
    }; 
    
  3. Использование ненавязчивого полиморфизм, при создании производного класса из любого класса, который хочет членство.

    struct ListInterface { // struct for defaulting to public 
        void Poke(uint addr, uint value) = 0; 
        uint Poke(uint addr) const = 0; 
    }; 
    
    class SplineVertex : public Vertex { 
        ... 
    }; 
    
    class SplineVertexHolder : public SplineVertex, public ListInterface { 
    }; 
    
Смежные вопросы