2010-09-28 3 views
2

У меня есть проект, в котором у меня много связанных классов Info, и я рассматривал возможность размещения иерархии с помощью класса AbstractInfo, а затем кучу производных классов, переопределяя реализации AbstractInfo по мере необходимости. Однако оказывается, что в C++ с использованием класса AbstractInfo для создания одного из производных объектов не так просто. (см. this вопрос, комментарий к последнему ответу)C++ factory and casting issue

Я собирался создать как фабричный класс, который создает объект Info и всегда возвращает объект AbstractInfo. Я знаю, что с C# вы можете делать это с интерфейсами, но на C++ все выглядит немного по-другому.

Вниз кастинг становится сложным делом и кажется склонным к ошибке.

У кого-нибудь есть лучшее предложение для моей проблемы?

+1

Можете ли вы рассказать о том, что вы подразумеваете под «не так просто»? – SingleNegationElimination

+1

В целом это должно быть проблемой только в том случае, если у вас нет полного интерфейса в 'AbstractInfo', т. Е. Вам нужно получить доступ к некоторым методам, которые определены только в подклассе. Но это также может означать, что ваш дизайн субоптимален. С этой небольшой информацией трудно сказать больше. –

ответ

5

Вы не нуждаетесь в сокращении. Смотрите этот пример:

class AbstractInfo 
{ 
public: 
    virtual ~AbstractInfo() {} 
    virtual void f() = 0; 
}; 

class ConcreteInfo1 : public AbstractInfo 
{ 
public: 
    void f() 
    { 
     cout<<"Info1::f()\n"; 
    } 
}; 

class ConcreteInfo2 : public AbstractInfo 
{ 
public: 
    void f() 
    { 
     cout<<"Info2::f()\n"; 
    } 
}; 

AbstractInfo* createInfo(int id) 
{ 
    AbstractInfo* pInfo = NULL; 
    switch(id) 
    { 
    case 1: 
     pInfo = new ConcreteInfo1; 
     break; 

    case 2: 
    default: 
     pInfo = new ConcreteInfo2; 
    } 

    return pInfo; 
} 


int main() 
{ 

    AbstractInfo* pInfo = createInfo(1); 
    pInfo->f(); 
    return 0; 
} 
1

Хотя обычно вы не можете перегрузить на типы возвращаемых значений в C++, есть исключение для covariant return types

Пример взят из википедии:

// Classes used as return types: 
class A { 
} 

class B : public A { 
} 

// Classes demonstrating method overriding: 
class C { 
    A* getFoo() { 
     return new A(); 
    } 
} 

class D : public C { 
    B* getFoo() { 
     return new B(); 
    } 
} 

Таким образом, отпадает необходимость в отливке.

+1

это не очень хорошо сформированный C++. – SingleNegationElimination

+1

'extends' - на каком языке это? И вы хотите вернуть указатель на вновь выделенный объект. Там нет завода. –

+1

Не код на C++. – Hemant

2

Не унывайте - используйте виртуальные методы. Просто верните указатель на базовый класс с фабрики и только работайте с этим указателем.

+0

Я вижу ... но если вы делаете AbstractInfo * info = new DerivedInfo(), вам нужно, по крайней мере, дать компилятору знать, какая версия виртуальной функции вам нужна, это не считается нисходящим? –

+0

Версия из самого производного класса будет вызываться автоматически, без необходимости понижения. – sharptooth

+3

Компилятор не нуждается ни в какой помощи при определении того, какой метод использовать. это то, что делает «виртуальный». когда вы вызываете виртуальный метод на указателе, компилятор знает, что значение действительно может быть другого производного типа. он исследует объект для своего типа, затем ищет соответствующий виртуальный метод. – SingleNegationElimination

1
class AbstractInfo 
{ 
    public: 
    virtual ~AbstractInfo(); 
    virtual X f(); 
    ... 
}; 

class Info_1 : public AbstractInfo 
{ 
    ... 
}; 

class Info_2 : public AbstractInfo 
{ 
    ... 
}; 

AbstractInfo* factory(inputs...) 
{ 
    if (conditions where you would want an Info_1) 
     return new Info_1(...); 
    else if (condtions for an Info_2) 
     return new Info_2(...); 
    else 
     moan_loudly(); 
} 

Если вы не хотите, фабричный метод, чтобы стать единой точкой обслуживания, как вниз по течению клиентского кода добавляет типы Info, вы можете вместо этого обеспечить некоторый механизм для клиентского кода для регистрации методов для создания этих производных объектов. Просмотрите книгу «Шаблоны дизайна банды четырех» для шаблонов творчества или их Google.

0

C++ обеспечивает polymorphism как раз как C#. Язык не имеет специального типа интерфейса, но вы можете эмулировать его, используя класс, который имеет только pure virtual methods. В C# все методы являются виртуальными по умолчанию (что означает, что они связаны во время выполнения), тогда как в C++ вы должны объявить, что явно используете ключевое слово virtual. Кроме того, C# обрабатывает все объекты, используя ссылки (насколько я знаю), тогда как в C++ вы должны выбирать между значениями, указателями или ссылками. В вашем случае вы, скорее всего, хотите, чтобы ваша фабрика вернула указатель на интерфейс или даже лучше smart pointer, так что вам не нужно беспокоиться об управлении памятью.

0

Для того, чтобы разработать/понтификровать немного, «хорошее» время использовать абстрактный интерфейс (например, базовый класс с виртуальными функциями) - это когда практически все функциональные возможности, которые будут использоваться на объектах, могут содержаться в виртуальных функциях. Если это так, вы можете сделать то, что вы предлагаете легко, и просто вызвать виртуальные функции на указателе базового класса, который автоматически выберет наиболее производную версию.

Если вам нужно часто опускаться, чтобы получить конкретные функции/данные для дочернего класса, этот подход, вероятно, не оптимален для вашей ситуации. В этом случае вы можете написать некоторые функции вне классов, предоставить несколько реализаций для каждого типа и использовать какой-то RTTI, чтобы помочь при необходимости сгладить. Это более беспорядочно, но, как правило, более распространено за пределами «академических» или хорошо изолированных способов использования.

Похоже, у вас есть много хорошей информации/совета здесь, в других ответах.