繁体   English   中英

如何在C ++中使用类似C#的属性

[英]How to use C#-like attributes in C++

我正在考虑将C ++用于个人项目。 我想让它独立于平台(没有单声道,因为有些平台还不支持它),这就是我考虑C ++的原因。

但是我有一个疑问。 我已经非常喜欢C#的属性了,我想知道我是否可以在C ++中使用类似的东西。

此外,是否可以使用装饰器模式?

编辑:我现在考虑其他可能性或近似值,即。 某种方式在运行时将其他行为附加到类。

编辑2:Java不是一个选项,因为有些设备我想将它移植到不支持java。

要在大多数OO语言中“在运行时向类附加其他行为”,我建议使用策略设计模式 - 保持类(和/或其实例)(通过C ++中的指针,其他语言中的[可重新配置]引用) )一个合适的接口/抽象类的实例,称为“策略接口”(使用一种方法[在C ++中虚拟,当然,在非最终语言中使用final ,等等 - IOW,一种可覆盖的方法! - )]每个可扩展性点),通常提供访问和更改该实例的getter和setter方法(或属性或适合特定语言的任何内容)。

最后,类或实例必须通过它所持有的策略接口实例的方法委派所有适当的功能。

我经常推荐这种“高礼式”方法(出于这个特定目的),即使在Python或Ruby这样的动态语言中也可以通过鸭子打字和类对象直接进入内部的能力来实现更多的非正式方法。另一种 - 这种动态能力通常说起来非常有用,但是出于这个特定的目的(我想到“在运行时改变一种类行为”),根据我的经验,一种更高度的架构和控制方法会带来更好的可维护性和更清晰的代码(这一点是有争议的:动态语言社区中的许多开发人员甚至在这种情况下都采用“猴子修补”方法,但是在动态语言(主要是Python)中进行了十几年的成功开发实践,这些都让我倾向于这样做。

在适当的情况下,您可以通过各种方式修改基本的战略DP方法; 例如,当可修改的功能整齐地落入几个有凝聚力的组中时,最好将Strategy对象“分段”为几个简单而有凝聚力的(DrawingStrategy,PersistenceStrategy,BusinessRulesStrategy等)。

这整个方法并不取代进行适当的分析,从而不能进行适当的设计,因为它不允许沿着最初未考虑的轴延伸类功能; 相反,该方法旨在作为构建经过深思熟虑的设计的正确方法,以良好控制的方式为可扩展性提供“钩子”。 如果新的考虑因素发挥作用,可能仍然需要迭代和完善课程的设计以涵盖这些新的想法。 但是,在任何丰富,复杂的现实项目中,迭代开发(包括对原始设计的调整和扩展)都是不可避免的 - 策略DP只是你箭袋中的一个箭头,有助于使流程更加有序和有效。

对于类属性,是的。 只需定义一个名为Attributes的基类来存储属性信息,并在任何需要属性的类中继承它。 您可以使用RTTI强制转换查询它。

但是对于方法或参数属性,这基本上不是一个选项。

关于如何使用模板特化“模拟”类属性的想法:

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

我们必须为我们希望它们应用的每个类应用(template-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#一样。 无论如何,快乐的编码!

构建一个预处理器,将语法等属性转换为实际属性和方法。

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的正确性。

属性描述元数据。 您可以通过继承基类来“手动”执行此操作,该基类为方法等类部件定义“描述”存储库。 但是,您需要在编译时使用部件的名称。

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

疼痛可能不值得受益......

您是否要求面向方面编程? AspectC ++目前只是一个研究原型:( http://www.aspectc.org/

我在CodeProject上读过一篇关于这个问题的文章: 带有Accessor-Modifiers的C#Property和Indexer的C ++实现 我相信这就是你想要的。

在您所指的MVC示例中,通过反射使用方法属性。 由于C ++没有反射,您可以考虑使用代码生成:某种接口定义语言和生成C ++代码的生成器。 在这种情况下,您可以自由地将属性概念添加到界面语言中,并使生成器以适当的方式转换属性。

一个很好的例子是Google 协议缓冲区 :有一种特殊的.proto格式用于定义消息,特别包括“选项”(非常接近.net属性的概念)。 还有不同编程语言的编译器,包括C ++。 后者为.proto格式描述的消息生成.h / .cpp文件。 生成的类特别提供反射功能,允许以编程方式检查是否已为服务/方法/消息/等设置了某些选项。

显然,代码生成方法并不容易实现,但它可以生成非常有效的解决方案。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM