views:

814

answers:

9

I'm considering the use of C++ for a personal project. I would like to make it platform independent (no Mono please, since some platforms don't yet support it), and that's why I considered C++.

I have one doubt, however. I've grown quite fond of C#'s attributes, and I would like to know if I can use something similar in C++.

Also, is it possible to use the decorator pattern for this?

EDIT: I would now consider other possibilities or approximations for this matter, ie. some way to attach additional behavior to a class in runtime.

EDIT 2: Java is not an option, because some devices I'd like to port it to don't support java.

+5  A: 

For class attributes, yes. Just define a base class called Attributes to store the attribute information, and inherit it in any class that needs attributes. You can query for it using RTTI cast.

But for method or parameter attributes, that's basically not an option.

Daniel Earwicker
as C++ supports multiple inheritance adding multiple attributes is easy :) this is however then bound to instances i guess
zproxy
A: 

C++0x will support limited attributes. But I doubt that will help you with your current project, or even you next few projects (it won't be here for a while).

I'll answer assuming you're referring to properties, a feature I've often covetted.

You can kinda support properties. A general implmentation of this would be bit more complex. But for one offs it can be easy

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;

I ignored const correctness for the sake of brevity.

caspin
changelog's comment makes it pretty clear it's about attributes, not properties.
Daniel Earwicker
There was a race between changelog's clarification and my response. This is a great example why multithreaded programming is difficult.
caspin
Multithreaded programming is hard. Lets go shopping! Now seriously, any ideas?
changelog
A: 

Attributes describe meta data. You could do that "manually" by inheriting from a base class that defines a repository of "descriptions" for class parts like methods. You would need the names of the parts at compile time though.

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

The pain is probably not worth the benefit...

EricSchaefer
A: 

In the MVC example you refer to, method attributes are used via reflection. Since C++ has no reflection, you may consider using code generation instead: some sort of interface definition language and a generator producing C++ code. In this scenario, you are free to add attribute concept to your interface language, and make the generator translate the attributes in an appropriate fashion.

A great example is Google protocol buffers: there is a special .proto format for defining messages, which in particular includes "options" (a concept very close to .net attributes). There are also compilers to different programming languages, including C++. The latter generates .h/.cpp files for the messages described by .proto format. The generated classes in particular provide reflection functionality, that allows checking programmatically if certain options have been set for services/methods/messages/etc.

Obviously, the code generation approach is not an easy one to implement, however it can produce very efficient solutions.

Sergii Volchkov
your answer suggests a template metaprogramming approach might obviate the need for the external code generator.
Jeff Leonard
+5  A: 

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.

Alex Martelli
+1  A: 

Are you asking for Aspect Oriented Programming? AspectC++ is currently just a research prototype :( http://www.aspectc.org/

Rob Fonseca-Ensor
+1  A: 

An idea on how to "simulate" a class attribute using template specialization:

#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 "";
    }
};

The default implementation of the attributes will be picked up by the compiler for a class without attributes:

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

If we want to apply the attributes to a class, we use template specialization:

// 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";
    }
};

We must apply (template-specialize) the attributes for every class we want them to be applied to:

class Item{
};

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

Example:

// 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;
}

In this way the attributes are "applied" to the class, and not to the instance as with multiple inheritance; the fundamental difference, anyway, is that in this case the attributes are evaluated at compile time, and not at run time.

EDIT: modified the example to show how to apply several attributes to a class and how to apply the same attribute to several classes.

Answering this question has been fun for me; at this point, anyway, I feel that the best advice on the subject is that you should not try to program in c++ as if it was c#. In any case, happy coding!

Paolo Tedesco
In this case, how would I apply several attributes to a class? Or do the classes have to be applied to the attribute?
changelog
The idea is to have the attributes applied to several classes. Imagine, if you will, a Rarity attribute for an Item class.
changelog
Wouldn't an Item require a Rarity *property* - since different instances of Item (sword, gold coin) could have different Rarities?
Rob Fonseca-Ensor
+2  A: 

Build yourself a preprocessor that turns an attribute like syntax into actual properties, and methods.

Christopher Karper
A: 

I had read a article on CodeProject about this issue: C++ implementation of the C# Property and Indexer with Accessor-Modifiers. I believe that is what you want.

yoco