C++实现的命令行参数管理(一)

2014-11-24 09:08:27 · 作者: · 浏览: 0

在编写可运行程序时,经常需要输入除了可运行文件之外的其它的命令行参数,可以用传统的getopt函数来分析,本文基于面向对象,分析一种管理命令行参数方法 -- 来源于webrtc项目,在阅读过程中,大家分享一下。

一,传统命令行分析

[cpp]
包含头文件:#include
  int getopt(int argc,char * const argv[ ],const char * optstring);
  extern char *optarg;
  extern int optind, opterr, optopt;

二,命令行参数管理
假设命令行的输入格式的规则如下:

--flag 布尔类型。
--noflag 布尔类型。
--flag=value 等号周边没有空格。
2.1 参数的值封装---FlagValue

这个类对参数的值进行封装,如--prefix=/usr,作为一个命令行参数时,prefix为键,/usr为值。在参数中,在此定义值的类型为布尔、整型、浮点、字符串中的一种。

由于一个值在只能取四种的一种,所以此处用联合类型表示FlagValue。

[cpp]
union FlagValue {
static FlagValue New_BOOL(int b) {
FlagValue v;
v.b = (b != 0);
return v;
}

static FlagValue New_INT(int i) {
FlagValue v;
v.i = i;
return v;
}

static FlagValue New_FLOAT(float f) {
FlagValue v;
v.f = f;
return v;
}

static FlagValue New_STRING(const char* s) {
FlagValue v;
v.s = s;
return v;
}

bool b;
int i;
double f;
const char* s;
};
这个联合类型对命令行中键值对中的值进行封装,可以表示四种类型。

2.2 命令行中键值的表示 -- Flag

这个类是表示一对键值的抽象,包含下列元素:

键值对。包括name和variable_表示键和值。如--prefix=/usr中,name的值为prefix,variable_为/usr的一个表示。
链表维护域。Flag *next_用于指向下一个命令行参数。
comment_表示该参数的解释。
file表示和键值相关的外部文件。
default_表示默认情况下,就是用户没有输入该参数的情况下默认的值。
定义友元类FlagList,因为FlagList需要访问Flag的next_域。
[cpp]
class Flag {
public:
enum Type { BOOL, INT, FLOAT, STRING };

// Internal use only.
Flag(const char* file, const char* name, const char* comment,
Type type, void* variable, FlagValue default_);

// General flag information
const char* file() const { return file_; }
const char* name() const { return name_; }
const char* comment() const { return comment_; }

// Flag type
Type type() const { return type_; }

// Flag variables
bool* bool_variable() const {
assert(type_ == BOOL);
return &variable_->b;
} www.2cto.com

int* int_variable() const {
assert(type_ == INT);
return &variable_->i;
}

double* float_variable() const {
assert(type_ == FLOAT);
return &variable_->f;
}

const char** string_variable() const {
assert(type_ == STRING);
return &variable_->s;
}

// Default values
bool bool_default() const {
assert(type_ == BOOL);
return default_.b;
}

int int_default() const {
assert(type_ == INT);
return default_.i;
}

double float_default() const {
assert(type_ == FLOAT);
return default_.f;
}

const char* string_default() const {
assert(type_ == STRING);
return default_.s;
}

// Resets a flag to its default value
void SetToDefault();

// Iteration support
Flag* next() const { return next_; }

// Prints flag information. The current flag value is only printed
// if print_current_value is set.
void Print(bool print_current_value);

private:
const char* file_;
const char* name_;
const char* comment_;

Type type_;
FlagValue* variable_;
FlagValue default_;

Flag* next_;

friend class FlagList; // accesses next_
};


2.3 命令行键值链表--- FlagList
这个类维护一个全局的链表,链表中每一项都是命令行参数解析的结果,如:--prefix=/usr --localstatedir=/var/data 这就表示两个Flag对象,通过Flag对象的next域来关联。

这个类的属性和方法都是静态的,属性只有Flag* list_,用于维护命令行所有输入的参数所组成的链表。

主要方法如下:

SetFkagsFromCommandLine:解析根据命令行的输入,这里传入的是所有的命令行输入。

SplitArgument:解析命令行中具体的一个可以被解析的键值对。

[cpp]
class FlagList {
public:
FlagList();

static Flag* list() { return list_; }

s