Как использовать атрибуты C#-like в C++

Я возьму его немного далее: полный код c, скомпилируйте и пойдите.

90 символов

main(int n,char**v){char*b,*e;b=e=v[1];while(*++e);for(e--;*b==*e&&b++<e--;);return b>e;}
11
задан changelog 28 July 2009 в 10:44
поделиться

9 ответов

To "attach additional behavior to a class in runtime" in most any OO language I recommend the Strategy design pattern -- have the class (and/or its instances) hold (through a pointer in C++, a [reseatable] reference in other languages) an instance of a suitable interface / abstract class known as the "strategy interface" (with one method [virtual in C++ of course, non-final in languages that have final, etc -- IOW, an overridable method!-)] per point of extensibility), and generally supply getter and setter methods (or properties or whatever's appropriate to the specific language) to access and change that instance.

Lastly, the class or instance must delegate all appropriate functionality through the methods of the strategy interface instance it's holding.

I often recommend this "high-ceremony" approach (for this specific purpose) even in dynamic languages such as Python or Ruby which would also allow more informal approaches via duck typing and the ability of an object of class to directly reach into the internals of another -- such dynamic abilities are generally speaking quite useful, but for this specific purpose (as I think of "changing a class behavior at runtime") a more highly architected and controlled approach, in my experience, leads to better-maintainable and clearer code (this bit is controversial: many developers in dynamic-language communities like "monkey patching" approaches even in such situations, but a dozen years of successful development practice in dynamic languages, mostly Python, have made me otherwise inclined).

In appropriate case you can modify the fundamental Strategy DP approach in various ways; for example, when the modifiable functionality falls neatly into a few cohesive groups, it's best to "fragment" the Strategy object into several simple and cohesive ones (DrawingStrategy, PersistenceStrategy, BusinessRulesStrategy, and so forth).

This whole approach does not take the place of performing proper analysis and consequently proper design, as it won't allow extension of a class functionality along an axis that was not originally taken into consideration; rather, the approach is intended as a proper way to architect a well-thought-out design, providing "hooks" for extensibility in a well-controlled manner. If new considerations come into play it may still well be necessary to iterate and perfect the classes' design to cover such new ideas. But then, iterative development (including tweaks and extensions to the original design) is inevitable in any rich, complex real-world project -- the Strategy DP is just one arrow in your quiver to help make the process more orderly and effective.

9
ответ дан 3 December 2019 в 04:53
поделиться

Для атрибутов класса - да. Просто определите базовый класс с именем Attributes для хранения информации об атрибутах и ​​унаследуйте его от любого класса, которому требуются атрибуты. Вы можете запросить его, используя RTTI cast.

Но для атрибутов метода или параметра это практически не вариант.

5
ответ дан 3 December 2019 в 04:53
поделиться

C ++ 0x будет поддерживать ограниченные атрибуты. Но я сомневаюсь, что это поможет вам в вашем текущем проекте или даже в следующих нескольких проектах (их здесь не будет какое-то время).

Я отвечу, предполагая, что вы имеете в виду свойства, функцию, которую я часто желанный.

Вы можете как бы поддержать свойства. В целом это было бы немного сложнее. Но для разовых работ это может быть легко

class Foo
{
    class MyI_property
    {
    public:
        MyI_property( Foo* parent ) :
            m_parent(parent)
        { }

        // getter
        operator int( void )
        { return m_parent->get_i(); }

        // setter
        MyI_property& operator = ( int i )
        { m_parent->set_i(i); }

        // some other operators you might want to implement
        int* operator&( void );
        MyI_property& operator += ( int rhs );

    private:
        Foo* m_parent;
    };

public:
    Foo( void ) :
        MyI(this)
    { }

    MyI_property MyI;

private:
    int& get_i( void );
    void set_i( int i );
};

Foo f;

f.MyI = 10; // calls Foo::set_i
int i = f.MyI; // calls Foo::get_i
int j = 2 * f.MyI + f.MyI;

// could work with proper overloads in MyI_property
f.MyI += 20;
int& i = f.MyI;
int* i = &f.MyI;

Ради краткости я проигнорировал корректность const.

1
ответ дан 3 December 2019 в 04:53
поделиться

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

class whatever
{
public:
    static map<string, string> attribute_repository;
}

Беда, вероятно, не стоит того ...

1
ответ дан 3 December 2019 в 04:53
поделиться

Идея о том, как «смоделировать» атрибут класса с помощью специализации шаблона:

#include <string>
#include <iostream>

// attribute classes: the default implementation returns some
// default values for the attributes properties
template<typename TheClass> 
struct Attribute1{
    static const int Value = 0;
};

template<typename TheClass> 
struct Attribute2{
    static const std::string Value(){
        return "";
    }
};

Реализация атрибутов по умолчанию будет выбрана компилятором для класса без атрибутов:

// define a type without attributes
struct ClassWithoutAttributes{
};

Если мы хотим применить атрибуты к классу, мы используем специализацию шаблона:

// define a type with attributes; we "simulate" the attributes     
// template specialization
struct ClassWithAttributes{
};

// template-specialize Attribute1 for the class we want to apply the
// attribute to...
template<>
struct Attribute1<ClassWithAttributes>{
    static const int Value = 1;
};

// template-specialize Attribute2 
template<>
struct Attribute2<ClassWithAttributes>{
    static const std::string Value(){
        return "SomeString";
    }
};

Мы должны применить (шаблон- specialize) атрибуты для каждого класса, к которому мы хотим их применить:

class Item{
};

template<>
struct Attribute1<Item>{
    static const int Value = 2;
};

Пример:

// how to use the fake attributes:
void main(){
    // no template specialization for "ClassWithoutAttributes" => the compiler picks up the "default" values
    std::cout << "Attribute1 for type 'ClassWithoutAttributes' : " << Attribute1<ClassWithoutAttributes>::Value << std::endl;
    std::cout << "Attribute2 for type 'ClassWithoutAttributes' : " << Attribute2<ClassWithoutAttributes>::Value() << std::endl;
    // here the compiler picks up the attribute classes specialized for "ClassWithAttributes"
    std::cout << "Attribute1 for type 'ClassWithAttributes' : " << Attribute1<ClassWithAttributes>::Value << std::endl;
    std::cout << "Attribute2 for type 'ClassWithAttributes' : " << Attribute2<ClassWithAttributes>::Value() << std::endl;
}

Таким образом, атрибуты «применяются» к классу, а не к экземпляру, как при множественном наследовании; в любом случае фундаментальное отличие состоит в том, что в этом случае атрибуты оцениваются во время компиляции, а не во время выполнения.

РЕДАКТИРОВАТЬ : изменен пример, чтобы показать, как применять несколько атрибутов к классу и как применять один и тот же атрибут для нескольких классов.

Мне было весело отвечать на этот вопрос; в любом случае, на этом этапе Я считаю, что лучший совет по этому поводу - не пытаться программировать на C ++, как если бы это был C #. В любом случае удачного кодирования!

3
ответ дан 3 December 2019 в 04:53
поделиться

Создайте препроцессор, который превращает атрибут, такой как синтаксис, в фактические свойства и методы.

2
ответ дан 3 December 2019 в 04:53
поделиться

Вы просите аспектно-ориентированное программирование? AspectC ++ в настоящее время является всего лишь исследовательским прототипом :( http://www.aspectc.org/

1
ответ дан 3 December 2019 в 04:53
поделиться

В примере MVC, на который вы ссылаетесь, атрибуты метода используются через отражение. Поскольку C ++ не имеет отражения, вы можете рассмотреть возможность использования вместо этого генерации кода: какого-то языка определения интерфейса и генератора, создающего код C ++. В этом сценарии вы можете добавить концепцию атрибута к своему языку интерфейса и заставить генератор преобразовывать атрибуты соответствующим образом.

Отличным примером являются буферы протокола Google : есть специальный .proto формат для определения сообщений, который, в частности, включает «опции» (концепция, очень близкая к атрибутам .net). Также существуют компиляторы для разных языков программирования, включая C ++. Последний генерирует файлы .h / .cpp для сообщений, описываемых форматом .proto.

0
ответ дан 3 December 2019 в 04:53
поделиться

Я прочитал статью на CodeProject об этой проблеме: Реализация C ++ свойства C # и индексатора с модификаторами доступа . Я считаю, что это то, что вам нужно.

1
ответ дан 3 December 2019 в 04:53
поделиться
Другие вопросы по тегам:

Похожие вопросы: