一个Java Enum的C++实现

Java 1.5提供了一个新的类型 - Enum,区别于传统C/C++的整型语义的枚举,Java的Enum为使用多态分支来取代 if/else 和 switch 这样的类型码相依逻辑的选择代码块提供了一个轻量级的实现,并同时具备传统的整型枚举语义与额外的便利的字符串语义 (可以获得枚举量对应的整型序号值与字符串值 oridinal toString,或通过字符串值获得对应的枚举量 valueOf)。

我写了一个类似的C++版本,用在自己的项目中,下面是它的实现,因为使用了QT库,所以string,vector,map都是使用QT的实现,不过也很容易替换为标准库的实现,于Java的实现稍有不同的是使用name而不是toString来获得枚举量字符串值,toString提供了更丰富的表示用于内部状态打印。


Enum.h

#pragma  once

#include 
< QString >
#include 
< QMap >
#include 
< QVector >
#include 
< iosfwd >


namespace milk
{
    
class  Enum
    
{
    
public:
        
/** Dump all Enum information out, only for debug. */
        
static void dump();
        
static void dump(std::ostream&);
    
protected:
        
/** A safe storage for store all enumerate items. */
        
static QMap<QString, QVector<const Enum*>>& EMAP();

        
/** Get all Enum items of the given Enum type. */
        
static QVector<const Enum*> values(const QString&);

        
/** Get the Enum items by it's type and name. */
        
static const Enum* valueOf(const QString&
            
const QString&);

    
private:
        QString        _type;
        QString        _name;
        
int            _ordinal;

        
//Constructor
    public:
        Enum(
const QString&const QString&);
        
virtual ~Enum(void);

    
public:
        
/** Get the Enum item's type. */
        QString type() 
const {return _type;}
        
/** Get the Enum item's name. */
        QString name() 
const {return _name;}
        
/** Get the Enum item's ordinal
        (the integer index in it's type, zero based) 
*/

        
int ordinal() const {return _ordinal;}
        
        
/** The represented string. */
        
virtual QString toString() const {return QString("[%1#%2]%3")
            .arg(type()).arg(ordinal()).arg(name());}


    
private:
        
/** Forbidden copy constructor and assignment operator. */
        Enum(
const Enum&);
        Enum
& operator=(const Enum&);
    }
;

    
/** Declare a new  Enum type. */
    
#define DECLARE_ENUM(ENUM_TYPE)/    
    
protected:/
        ENUM_TYPE(
const QString& ename) : Enum(QString(#ENUM_TYPE), ename) {}/
    
public:/
        
static QVector<const ENUM_TYPE *> values(){/
            QVector
<const ENUM_TYPE *> ret;/
            
foreach(const Enum * en, Enum::values(QString(#ENUM_TYPE)))/
            
{/
                
const ENUM_TYPE * ct = dynamic_cast<const ENUM_TYPE *>(en);/
                
if (ct) ret.push_back(ct);/
            }/

            
return ret;/
        }/

        
static const ENUM_TYPE* valueOf(const QString& ename){/
            
return  dynamic_cast<const ENUM_TYPE *>(Enum::valueOf(QString(#ENUM_TYPE), ename));/
        }


}



Enum.cpp

#include  < cassert >
#include 
< iostream >

#include 
" Enum.h "

namespace  milk
{
    Enum::Enum(
const QString& type, const QString& name)
        : _type(type), _name(name)
    
{
        QMap
<QString, QVector<const Enum*>>& emap = EMAP();
        
if (!emap.contains(type))
        
{
            
//Insert a new vector for the new Enum type
            QVector<const Enum*> newEnums;
            emap.insert(type, newEnums);

        }


        QVector
<const Enum*>& enums = emap[type];
        enums.append(
this);
        _ordinal 
= enums.size() - 1;
    }


    Enum::
~Enum(void)
    
{
    }


    QMap
<QString, QVector<const Enum*>>& Enum::EMAP()
    
{
        
static QMap<QString, QVector<const Enum*>> emap;
        
return emap;
    }


    QVector
<const Enum*> Enum::values(const QString& type)
    
{
        
return EMAP()[type];
    }


    
const Enum* Enum::valueOf(const QString& type, const QString& name)
    
{
        
foreach(const Enum* em, Enum::values(type))
        
{
            
if (em->name() == name)
                
return em;
        }

        
return 0;
    }


    
void Enum::dump(std::ostream& os)
    
{
        QMap
<QString, QVector<const Enum*>>& emap = EMAP();
        
foreach(QString key, emap.keys())
        
{
            os
<<" ";
            
foreach(const Enum* em, emap[key])
            
{
                os
<<qPrintable(em->toString())<<" ";
            }

        }

    }


    
void Enum::dump()
    
{
        QMap
<QString, QVector<const Enum*>>& emap = EMAP();
        
foreach(QString key, emap.keys())
        
{
            std::cout
<<" ";
            
foreach(const Enum* em, emap[key])
            
{
                std::cout
<<qPrintable(em->toString())<<" ";
            }

        }

    }

}


头文件里面定义了一个 DECLARE_ENUM宏,用来为从Enum类派生的枚举类型生成一个构造函数和values 与valueOf 函数。

因为不能像Java一样由编译器自动生成辅助代码,所以使用上(枚举类型和枚举量的定义)会比Java要复杂一些,不过相对而言,也比较灵活一些。

下面是定义一个枚举类型的示例:

#pragma  once
#include 
< QImage >

#include 
" ../Core/Enum.h "
#include 
" AnalysisResult.h "

namespace  milk
{
    
class AnalysisInput;

    
class  IQAnalyser : public Enum
    
{
        DECLARE_ENUM(IQAnalyser)

    
public:
        
/** Analysis method. */
        SP_AnalysisResult analysis(
const AnalysisInput& input) const
        
{
            
return analysisInt(input);
        }


        
/** Export result method. */
        
void exportResult(SP_AnalysisResult result, const QString& exFile) const
        
{
            
return exportResultInt(result, exFile);
        }


        QString chartType() 
const {return chartTypeInt();}

    
private:
        
virtual SP_AnalysisResult 
            analysisInt(
const AnalysisInput&const = 0;
        
virtual void 
            exportResultInt(SP_AnalysisResult, 
const QString&const = 0;
        
virtual QString chartTypeInt() const = 0;
    
private:
        IQAnalyser(
const IQAnalyser&);
        IQAnalyser
& operator=(const IQAnalyser&);
    }
;
}



接下来我们在实际使用中就可以为这个枚举类型派生出多个子类型,并为每个子类型生成一个单件常量(枚举量),类似这样:

ISO13660Analyser.h

#pragma  once
#include 
< PureMilk / Analyser / IQAnalyser.h >
#include 
< QString >

namespace  milk
{
    
class IS013660Analyser : public IQAnalyser
    
{
    
private:
        IS013660Analyser(
const QString& name): IQAnalyser(name){}

        
virtual SP_AnalysisResult 
            analysisInt(
const AnalysisInput&const;

        
virtual void 
            exportResultInt(SP_AnalysisResult, 
const QString&const;

        
virtual QString chartTypeInt() const
        
{
            
return QString("ISO-13660");
        }


    
public:
        
static const IQAnalyser* ISO13660_ANALYSER;
    }
;
}



#include  " IS013660Analyser.h "


namespace  milk
{
    
const IQAnalyser* IS013660Analyser::ISO13660_ANALYSER = 
        
new IS013660Analyser("ISO-13660 Analyser");

        ... ... ... ...
}

如果需要访问某个特定的枚举量,子类型的单件声明也可以放在父类型里,像Java的实现一样,不过并没有Java那样必须如此的限制。

以上的实现在UI界面的呈现上会有巨大的便利,我们可以通过枚举类型的values调用获得整个枚举量的集合,把它们的名字放在列表框或者下拉选框中让用户选择。然后把用户的选择使用多态自动派遣到具体的实现逻辑中去。




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值