madf: (Default)
[personal profile] madf
Їздив на вихідних на батьківщину. Поки їхав потягом - вирішив перевірити, чи не зовсім ще мозок засох у мене. За пару днів до цього, працюючи над своїм улюбленим Stargazer'ом, стикнувся із задачкою: треба було дістати значення деяких полів об'єкту за їх іменами. Імена відомі лише під час виконання програми (Run-Time). Всілякі різновидності RTTI та вказівники на void не підходять за параметрами. Та і архітектурно вони виглядають погано.
Доступ до змінної за її іменем під час виконання програми э тривіальною операцією для скриптових (інтерпретованих) мов програмування. Для компіляторів така задача, зазвичай, не під силу. Наприклад, такого немає ні у мові програмування Pascal, ні у C. Такого немає і у мові програмування C++. Але ця мова настільки потужна, що дозволяє реалізувати щось подібне.
З першого погляду задача здається нерозв'язною. Я декілька годин сидів, дивлячись на наявний код. Потім штудіював Александреску. Спробував "прикрутити" його списки типів. Але це все не те. А що те? Фактично мені було достатньо отримати значення змінної у вигляді std::string;
Клас, що займається серіалізацією, має бути шаблонним. Це факт. Бо інакше треба буде створити по екземпляру класу на кожний тип. А це незручно і для мене і для користувача. В чому "фішка" шаблонного класу? Він "спрацьовує" лише на етапі компіляції. А імена змінних я буду знати на етапі виконання. Погано.


template <typename T>
class Property {
public:
Property(const std::string & n,
T & v)
: name(n),
val(v)
{
}

std::string GetString() const
{
std::stringstream stream;

stream << val;

return stream.str();
}
private:
std::string name;
T & val;
};


Наведений код неможливо "засунути" у std::map, бо неможливо створити гетерогенний контейнер. У той же час, на етапі виконання програми спрацьовує одна із основних ідей ООП - поліморфізм. А що, ідея! Створити такий базовий класс, що надає користувачу можливість отримати серіалізований рядок, а ініціалізувати його використовуючи шаблонний класс. Після компіляції у області пам'яті, на яку вказує базовий клас, буде створено код, що відповідає за серіалізацію відповідного типу. На етапі компіляції працюють шаблони, а на
етапі виконання - поліморфізм.


class BaseProperty {
public:
virtual std::string GetString() const = 0;
};

template<typename T>
class Property : public BaseProperty {
public:
Property(const std::string & n,
T & v)
: name(n),
val(v)
{
}

virtual std::string GetString() const
{
std::stringstream stream;

stream << val;

return stream.str();
}
private:
std::string name;
T & val;
};


Такий код вже можна одавати до контейнеру:


int a(0);
double b(3.14159265359);
std::string c("Hello World!");
std::map<std::string, BaseProperty *> props;

props["a"] = new Property<int>("a", a);
props["b"] = new Property<int>("b", b);
props["c"] = new Property<int>("c", c);

std::cout << "a = " << props["a"]->GetString() << std::endl;
std::cout << "b = " << props["b"]->GetString() << std::endl;
std::cout << "c = " << props["c"]->GetString() << std::endl;


Або щось на кщталт цього :)
C++ - forever!

Profile

madf: (Default)
madf

April 2018

S M T W T F S
1234567
891011121314
15161718192021
22232425262728
2930     

Most Popular Tags

Style Credit

Expand Cut Tags

No cut tags
Page generated Jun. 8th, 2026 04:11 pm
Powered by Dreamwidth Studios