C ++结构初始化
是否有可能在C ++中初始化结构如下所示
struct address { int street_no; char *street_name; char *city; char *prov; char *postal_code; }; address temp_address = { .city = "Hamilton", .prov = "Ontario" };
这里和这里的链接提到只有在C中才可以使用这种风格。如果是这样,为什么在C ++中这是不可能的? 有没有任何基本的技术原因,为什么不用C ++实现,或者是不好的做法,使用这种风格。 我喜欢使用这种初始化方式,因为我的结构很大,这种风格给了我清晰的可读性赋值给哪个成员。
请与我分享,如果有其他的方式,我们可以达到相同的可读性。
在发布这个问题之前,我已经提到了以下链接
- C / C ++ for AIX
- Cvariables的结构初始化
- 在C ++中使用标签的静态结构初始化
- C ++ 11适当的结构初始化
如果你想清楚每个初始值是什么,就把它分成多行,每行都有一个注释:
address temp_addres = { 0, // street_no nullptr, // street_name "Hamilton", // city "Ontario", // prov nullptr, // postal_code };
在我的问题导致没有令人满意的结果(因为C ++没有实现结构的基于标签的init),我采取了我在这里发现的技巧: 默认情况下,C ++结构的成员初始化为0?
对你来说,这可以做到这一点:
address temp_address = {}; // will zero all fields in C++ temp_address.city = "Hamilton"; temp_address.prov = "Ontario";
这当然是最接近你最初想要的(除了你想要初始化的所有字段之外的零)。
字段标识符的确是C初始化语法。 在C ++中,只需按照正确的顺序给出值,而不使用字段名称。 不幸的是,这意味着你需要给他们所有的(实际上你可以省略尾随的零值字段,结果将是相同的):
address temp_address = { 0, 0, "Hamilton", "Ontario", 0 };
你甚至可以将Gui13的解决scheme打包成单个初始化语句:
struct address { int street_no; char *street_name; char *city; char *prov; char *postal_code; }; address ta = (ta = address(), ta.city = "Hamilton", ta.prov = "Ontario", ta);
免责声明:我不推荐这种风格
你可以通过ctor初始化:
struct address { address() : city("Hamilton"), prov("Ontario") {} int street_no; char *street_name; char *city; char *prov; char *postal_code; };
它没有在C ++中实现。 (也char*
string?我希望不是)。
通常如果你有这么多的参数,这是一个相当严重的代码味道。 但是,相反,为什么不简单地重新初始化结构,然后分配每个成员?
这个function被称为指定初始值设定项 。 这是C99标准的补充。 但是,这个function被排除在C ++ 11之外。 根据C ++编程语言第4版第44.3.3.2节(C ++不采用C特性):
在C ++中有一些补充C99(与C89相比)故意不采用:
[1]可变长度数组(VLA); 使用vector或某种forms的dynamic数组
[2]指定的初始化程序; 使用构造函数
C99语法具有指定的初始值 [参见ISO / IEC 9899:2011,N1570委员会草案 – 2011年4月12日]
6.7.9初始化
initializer: assignment-expression { initializer-list } { initializer-list , } initializer-list: designation_opt initializer initializer-list , designationopt initializer designation: designator-list = designator-list: designator designator-list designator designator: [ constant-expression ] . identifier
另一方面,C ++ 11没有指定的初始化器 [参见ISO / IEC 14882:2011,N3690委员会草案 – 2013年5月15日]
8.5初始化器
initializer: brace-or-equal-initializer ( expression-list ) brace-or-equal-initializer: = initializer-clause braced-init-list initializer-clause: assignment-expression braced-init-list initializer-list: initializer-clause ...opt initializer-list , initializer-clause ...opt braced-init-list: { initializer-list ,opt } { }
为了达到相同的效果,使用构造函数或初始值设定项列表:
我知道这个问题是相当古老的,但我发现了另一种初始化的方式,使用constexpr和currying:
struct mp_struct_t { public: constexpr mp_struct_t(int member1) : mp_struct_t(member1, 0, 0) {} constexpr mp_struct_t(int member1, int member2, int member3) : member1(member1), member2(member2), member3(member3) {} constexpr mp_struct_t another_member(int member) { return {member1, member, member2}; } constexpr mp_struct_t yet_another_one(int member) { return {member1, member2, member}; } int member1, member2, member3; }; static mp_struct_t a_struct = mp_struct_t{1} .another_member(2) .yet_another_one(3);
这个方法也适用于全局静态variables,甚至是constexpr。 唯一的缺点是可维护性差:每次使用此方法都必须使另一个成员初始化时,所有成员初始化方法都必须更改。
我发现这样做的全局variables,不需要修改原来的结构定义:
struct address { int street_no; char *street_name; char *city; char *prov; char *postal_code; };
然后声明从原始结构typesinheritance的新types的variables,并使用字段初始化的构造函数:
struct temp_address : address { temp_address() { city = "Hamilton"; prov = "Ontario"; } } temp_address;
虽然不像C风格那么优雅
对于局部variables也应该是可能的,但是需要检查是否需要附加的memset(this,0,sizeof(* this))然后…
(请注意,'temp_address'是一个'temp_address'types的variables,但是这个新typesinheritance自'address',并且可以用在每个需要'address'的地方,所以没关系。
这是可能的,但只有当你正在初始化的结构是一个POD(普通的旧数据)结构。 它不能包含任何方法,构造函数,甚至默认值。
在C ++中,C风格的初始值设定项被构造函数取代,编译时间可以确保只执行有效的初始化(即初始化对象成员一致后)。
这是一个很好的做法,但是有时候预先初始化是很方便的,就像在你的例子中一样。 OOP通过抽象类或创builddevise模式来解决这个问题。
在我看来,使用这种安全的方式杀死了简单性,有时安全权衡可能太昂贵,因为简单的代码不需要复杂的devise来保持可维护性。
作为另一种解决scheme,我build议使用lambdas来定义macros以简化初始化,使其看起来几乎像C风格一样:
struct address { int street_no; const char *street_name; const char *city; const char *prov; const char *postal_code; }; #define ADDRESS_OPEN [] { address _={}; #define ADDRESS_CLOSE ; return _; }() #define ADDRESS(x) ADDRESS_OPEN x ADDRESS_CLOSE
ADDRESSmacros扩展到
[] { address _={}; /* definition... */ ; return _; }()
它创build并调用lambda。 macros参数也是用逗号分隔的,所以你需要把初始化程序放在括号内,并且像这样调用
address temp_address = ADDRESS(( _.city = "Hamilton", _.prov = "Ontario" ));
你也可以编写泛化的macros初始值设定项
#define INIT_OPEN(type) [] { type _={}; #define INIT_CLOSE ; return _; }() #define INIT(type,x) INIT_OPEN(type) x INIT_CLOSE
但是那个电话稍微不漂亮
address temp_address = INIT(address,( _.city = "Hamilton", _.prov = "Ontario" ));
不过你可以很容易的使用一般的INITmacros来定义ADDRESSmacros
#define ADDRESS(x) INIT(address,x)
我今天遇到类似的问题,我有一个结构,我想填充testing数据,将作为parameter passing给我testing的函数。 我想有一个这些结构的向量,并正在寻找一个单线程的方法来初始化每个结构。
我最终在结构体中使用了一个构造函数,我相信在你的问题中也有一些答案。
让构造函数的参数具有与公共成员variables相同的名字可能是不好的做法,需要使用this
指针。 如果有更好的方法,有人可以build议编辑。
typedef struct testdatum_s { public: std::string argument1; std::string argument2; std::string argument3; std::string argument4; int count; testdatum_s ( std::string argument1, std::string argument2, std::string argument3, std::string argument4, int count) { this->rotation = argument1; this->tstamp = argument2; this->auth = argument3; this->answer = argument4; this->count = count; } } testdatum;
我在我的testing函数中使用了以下各种参数来调用正在testing的函数:
std::vector<testdatum> testdata; testdata.push_back(testdatum("val11", "val12", "val13", "val14", 5)); testdata.push_back(testdatum("val21", "val22", "val23", "val24", 1)); testdata.push_back(testdatum("val31", "val32", "val33", "val34", 7)); for (std::vector<testdatum>::iterator i = testdata.begin(); i != testdata.end(); ++i) { function_in_test(i->argument1, i->argument2, i->argument3, i->argument4m i->count); }
你可以使用extern“C”来编译C ++中的c代码。 在你的情况下,你可以使用下面的代码
extern "C" { //write your C code which you want to compile in C++ struct address { int street_no; char *street_name;`enter code here` char *city; char *prov; char *postal_code; }; address temp_address ={ .city = "Hamilton", .prov = "Ontario" }; }