Pull to refresh
19
0
Send message
Я делал нечто подобное, но с использованием шаблонов.
Моей задачей было написание класса настроек с сериализацией в реестр или в файл.

Поля класса (структуры) я описывал при помощи шаблонных объектов-оболочек с общим базовым
интерфейсом (для хранения в общем списке).
При этом класс-оболочка вел себя как «умный» указатель, то есть имитировал стандартный синтаксис доступа к членам структуры.

В примитивном виде это было как-то так:
template<typename T>
class CValue : public IValue
{...};

class CMyStruct
{
public:
    CValue<int>          id;
    CValue<std::string>  name;
private:
    std::vector<IValue*> m_values;
};

Каждый объект CValue в своем конструкторе регистрирует себя в общем списке m_values.
После чего список m_values можно использовать для обхода объектов с целью сравнения или сериализации (шаблон визитор).

В итоге получилась довольно интересная штуковина.
Нет, этот код ужасен не по этой причине.
Этот код перегружен синтаксисом ЯП, также нарушена инкапсуляция, т.к. наружу торчит реализация:
x => Alert("pot " + x)
Так, как ты мне тут тыкаешь, то с тобой мне точно больше говорить не о чем!
1. Где вы вообще увидели MFC, и что за претензии к использованию C++11 в 2012 году?

2. std::set в примере, т.к. мне нужно было написать пример быстро и по сути (оригинальный код я показать не могу).
В оригинале у меня std::map с хитрым составным ключом, включающим в себя type_info + строчку.
Таким образом, что результатом поиска может быть только объект определенного типа (так же, как и в примере с std::set). Единственное отличие при использовании std::map это то, что я могу добавлять в контейнер любое количество объектов разного типа с нулевым ID (как и в примере), и несколько объектов одного типа с разными ID:
A* a = container.GetObject<A>();
B* b1 = container.GetObject<B>("b1");
B* b2 = container.GetObject<B>("b2");

В общем, оригинальный пример мне показался перегруженным и я сократил его до std::set.

3. type_info::berofre() возвращает int, а не bool.
IMHO, читабельность и простоту кода нельзя приносить в жертву ради избежания копирования пары строчек.

Этот код хорош, потому что он простой:
Console.WriteLine(“get the lobster”);
PutInPot(“water”);
PutInPot(“lobster”);


И этот код смотрится хорошо:
Cook(“lobster”, “water”, PutInPot);

Но вариант с лямбда функциями просто ужасен:
Cook("lobster",
          "water",
          x => Alert("pot " + x));
>>Если вы в данном контексте знаете конкретный класс, зачем его конструировать через фабрику?
Клиентский код может иметь доступ к декларации класса, но при этом не уметь его конструировать.

Конечно, все зависит от конкретной ситуации, я просто делал нечто подобное и вспомнил об этом.
Пример того, что я делал см. ниже.
Хочу привести пример IOC контейнера, о котором я упоминал:

class CContainer
{
    struct SortPred
    {
    public:
        bool operator ()(const boost::any& one, const boost::any& two)
        {
            return one.type().before(two.type()) ? true : false;
        }
    };
    std::set<boost::any, SortPred> m_objects;

public:
    template<typename T>
    void RegisterObject(T* pT)
    {
        m_objects.insert(boost::any(pT));
    }
    template<typename T>
    T* GetObject()const
    {
        T* pT = NULL;
        auto iter = m_objects.find(boost::any(pT));
        if (iter == m_objects.end())
        {
            return NULL;
        }
        return boost::any_cast<T*>(*iter);
    }
    template<typename T>
    void UnregisterObject(T* pT)
    {
        auto iter = m_objects.find(boost::any(pT));
        if (iter != m_objects.end())
        {
            m_objects.erase(iter);
        }
    }
};
Что Вы будете делать в случае, если создаваемому объекту понадобится некий параметр при конструировании?
Как по мне, то регистрировать стоит не конечный класс, а его билдер, либо уже созданный объект класса с клонированием (прототип).

Еще, при необходимости, можно сделать шаблонный метод для конструирования классов конкретного типа (не базового). Это позволит в некоторых случаях избежать нежелательной конвертации к классу-наследнику.
Я использовал похожую конструкцию как IoC контейнер, но там у меня хранились объекты разных классов без общего предка (по принципу boost::any).
У нас был случай на работе: сотруднику пришла пустая коробка с Kindle Keyboard 3G.
Устройство вытянули где-то в аэропорту, разодрав боковину коробки, при этом отрывная полоска была цела. В итоге амазон бесплатно отправил еще одно устройство, но впечатление было испорчено…
Мне кажется, что не совсем корректно говорить о 2010 студии, т.к. как минимум представления типов работают и в 2005 студии тоже.
Я так понял что Вы проверяли Ваши надстройки только для 2010 студии, а для более ранних поленились?
Вывод в консоль или в файл влияет на работу программ.
Например, многопоточные программы в некоторых случаях могут продолжать работать при включенных логах, но начинают падать при отключении логирования.
Без отладчика можно только предполагать что делает программа, под отладчиком — видеть как программа выполняется. Особенно, если эта программа не покрыта юнит-тестами, или взаимодействует с другими программами.

Отладчик в ряде случаев просто незаменим:
* Отладка приложений при загрузке/выгрузке системы с использованием ядерного отладчика (сервисы, boot-time приложения (autochk.exe), драйвера).
* Анализ креш-дампов.

Какой смысл не использовать готовый, надежный инструмент в пользу наколенных решений в виде логов?
>>да и не может использоваться в kernel окружении
Вы не правы, C++ успешно используется для написания драйверов.
Для написания драйвера на C++ нужно не так уж много:

1) Перегрузить глобальные операторы new/delete:
void *__cdecl operator new(size_t size, unsigned long tag, POOL_TYPE pool);
void __cdecl operator delete(void* p);


2) Не пользоваться глобальными объектами или реализовать initterm/atexit для вызова конструкторов/деструкторов глобальных объектов;

3) Использовать C++ по минимуму (мы не использовали С++ exceptions и сторонние библиотеки, даже STL)
Я вообще не понимаю зачем делать драйвер для принтера/сканера в виде драйвера, а не user-mode приложения, особенно если этот принтер/сканер сетевой?
С интересом проводить время это конечно хорошо, но реальность такова, что приходится всю жизнь горбатиться чтобы купить 1-комнатную квартиру в Москве/Киеве.
>>А теперь время магии.

Да никакой магии нет, notepad.exe не заморачивается (так же как и большинство других программ) и ведет себя простым образом, то есть запускается с правами администратора, и все окна, а также дочерние процессы, создаваемые в нем, наследуют эти права.

Explorer.exe спроектирован по другому, он стремится всегда быть запущенным с минимальными правами и предоставлять разширенные права по мере надобности.

Только что провел интересный эксперимент — под лимитированным пользователем прибил процесс explorer.exe, а затем запустил его от имени администратора и получил shell, запущенный от админа, но после того, как я попытался запустить explorer как файловый менеджер, то получил еще один экземпляр процесса с лимитированными правами.

В общем намутили они с этим explorer-ом, а вот с блокнотом все предельно ясно, и нет там никакой магии.
Драйвера на C проще, т.к. есть готовые декларации функций, поставляемые с WDK.
На другом языке программирования Вам пришлось писать декларации импортируемых функций вручную, и вручную же гарантировать их корректность.
Кстати, стоит упомянуть еще о статическом анализаторе PREFast, который заточен под C.
Или еще лучше — выпускать планшеты с некой наклейкой, которая будет немного менять вид устройства :)
Сегодня маркетологи Киевстара взорвали мне мозг следующей записью:
«Тарификация… звонков… является посекундной и осуществляется в первую секунду каждой минуты разговора, секунды со второй по шестидесятую каждой минуты разговора не тарифицируются.»

Information

Rating
Does not participate
Registered
Activity