将 C 风格结构与 C++ 混合
Mixing C-Style Structures with C++
我不是 C++ 期望的,您无疑会注意到。但我正在尝试 "upgrade" 一些旧的 C 代码到 C++。在此过程中,我试图将旧结构提升为 classes。我发现这篇 Oracle 文章介绍了我正在尝试做的一些事情。
http://www.oracle.com/technetwork/articles/servers-storage-dev/mixingcandcpluspluscode-305840.html
但是有两件事。这篇文章没有解决我遇到的更复杂的案例。而我的 "workaround" 似乎并没有导致一致的结果。所以我在这里详细介绍一下。
旧的 C 风格结构:
typedef struct
{
int ia;
float fa;
...
} Struct_A;
typedef struct
{
Struct_A sA;
int ib;
float fb;
...
} Struct_B;
C++
根据 Oracle 文章,我应该能够将 Struct_A 提升为 class,并且仍然能够使用具有旧 C 函数的 class 版本。显然是这样:
class CStruct_A : public Struct_A // Inherits from C- Struct_A
{
public:
CStruct_A() : ia(0), fa(0.0f) {}
}
暂停。就在这里,我已经有一个问题。我似乎无法按照文章中和上面所示的那样初始化 C 结构元素。编译器不接受它。我必须将 class 重写为:
class CStruct_A : public Struct_A
{
public:
CStruct_A()
{
ia = 0;
fa = 0.0f;
}
}
这是第一个问号。没什么大不了的,但是文章声称可以做到。
接下来是更棘手的问题。提升 Struct_B,其中包含 Struct_A 成员。我想确保 Class A 的构造函数用于初始化变量。但我不确定如何强制执行。在我的 C++ 代码中,如果我有类似的东西:
{
CStruct_B *pCStrb = new CStruct_B();
...
}
Class B 的构造函数被调用而不是 class A 的构造函数。我的解决方法很蹩脚......但这是我现在唯一能想到的。我在 class A 中声明了一个内部私有函数 ini(),使 class B 成为朋友并从 class B 的构造函数中调用 init()。
class CStruct_A : public Struct_A
{
friend class CStruct_B;
public:
CStruct_A() { init(); }
private:
void init()
{
ia = 0;
fa = 0.0f;
}
}
class CStruct_B : public Struct_B
{
public:
CStruct_B()
{
ib = 0;
fb = 0.0f;
static_cast<CStruct_A *>(&sA)->init();
}
}
我还有更多问题,但这可能已经太长了。
任何帮助将不胜感激。
我浏览了您引用的 "Oracle article",但在那篇文章中没有发现任何内容表明您可以按照您声称的文章描述或提供的方式初始化基础 classes任何接近您要编译的语法的示例。
C++ classes 的构造函数只能初始化其 class 的成员。它们不能直接从它们的构造函数初始化它们的 superclass 的任何成员。
话虽如此,一些编译器可能会提供它们自己的特定于编译器的语言扩展。例如,gcc 5.1 将在 -std=c++11 模式下接受以下代码:
typedef struct
{
int ia;
float fa;
} Struct_A;
class CStruct_A : public Struct_A {
public:
CStruct_A() : Struct_A({
.ia=1,
.fa=0,
})
{
}
};
但是,这非常低效并且不是标准的 C++(因为 gcc 会在 -Wpedantic
模式下警告您)。
解决您的第一个问题。从 C++ 的角度来看,这些 C 结构被认为是聚合。所以你可以这样做:
class CStruct_A : public Struct_A
{
public:
CStruct_A() : Struct_A{0, 0.0f} {};
}
这非常适合我。大括号初始化程序只是按照其成员的顺序初始化 Struct_A。
我认为处理您的第二个问题的最佳方法是将 CStruct_A 隐式转换回 Struct_A,然后使用它。
struct A {
double x;
int y;
};
class Ac : public A {
public:
Ac() : A{0.0, 1} {};
operator A() const { return A{x, y}; }
};
struct B {
B() : a(Ac()) {};
A a;
};
编辑:综上所述,我不太确定继承是解决此问题的首选。我几乎肯定宁愿从用 C++ 类 封装 C 风格的结构开始,然后从那里开始。
详细说明我将如何做到这一点:
class CStruct_A {
// ... various other code, initializes a carefully etc
public:
Struct_A * getA() { return &a; }
private:
Struct_A a;
}
现在,给出一些函数:
void func(Struct_A * var);
这样称呼它:
CStruct_A my_var();
func(my_var.getA());
它可能不像使用继承那么花哨,但它简单,有效,它允许您完全封装 C 结构并决定它们的初始化方式,编译器会保护您免于意外调用 func(myvar)等。我更喜欢这个而不是继承,除非有比你概述的更有说服力的理由使用继承。
好的...
为了结束这个问题,我想我发现初始化子结构的唯一方法几乎就是按照我在解决方法中所做的。我还没有找到另一种直接的方法。我想这没什么大不了的。我只是被原文误导了。
现在,旧代码有一个定义为 "extern" 的全局 Struct_B,我的新 C++ 程序必须分配它。为了能够使用其提升的功能,同时从旧的 C 代码角度来看仍然是 "defined",我将其声明为:
{
Struct_B *pCStrb = new CStruct_B();
...
}
所以我将它声明为旧的 c 结构,但使用 class 版本分配它。这与我最初在上面写的不同,我在上面使用 "C++" 版本来声明它。这显然是错误的,因为旧的 C 代码对名为 CStruct_B.
的结构一无所知
总之...似乎正在做我想做的事,尽管不完全是 "as" 我想要的。
感谢您的帮助。
我不是 C++ 期望的,您无疑会注意到。但我正在尝试 "upgrade" 一些旧的 C 代码到 C++。在此过程中,我试图将旧结构提升为 classes。我发现这篇 Oracle 文章介绍了我正在尝试做的一些事情。
http://www.oracle.com/technetwork/articles/servers-storage-dev/mixingcandcpluspluscode-305840.html
但是有两件事。这篇文章没有解决我遇到的更复杂的案例。而我的 "workaround" 似乎并没有导致一致的结果。所以我在这里详细介绍一下。
旧的 C 风格结构:
typedef struct
{
int ia;
float fa;
...
} Struct_A;
typedef struct
{
Struct_A sA;
int ib;
float fb;
...
} Struct_B;
C++
根据 Oracle 文章,我应该能够将 Struct_A 提升为 class,并且仍然能够使用具有旧 C 函数的 class 版本。显然是这样:
class CStruct_A : public Struct_A // Inherits from C- Struct_A
{
public:
CStruct_A() : ia(0), fa(0.0f) {}
}
暂停。就在这里,我已经有一个问题。我似乎无法按照文章中和上面所示的那样初始化 C 结构元素。编译器不接受它。我必须将 class 重写为:
class CStruct_A : public Struct_A
{
public:
CStruct_A()
{
ia = 0;
fa = 0.0f;
}
}
这是第一个问号。没什么大不了的,但是文章声称可以做到。
接下来是更棘手的问题。提升 Struct_B,其中包含 Struct_A 成员。我想确保 Class A 的构造函数用于初始化变量。但我不确定如何强制执行。在我的 C++ 代码中,如果我有类似的东西:
{
CStruct_B *pCStrb = new CStruct_B();
...
}
Class B 的构造函数被调用而不是 class A 的构造函数。我的解决方法很蹩脚......但这是我现在唯一能想到的。我在 class A 中声明了一个内部私有函数 ini(),使 class B 成为朋友并从 class B 的构造函数中调用 init()。
class CStruct_A : public Struct_A
{
friend class CStruct_B;
public:
CStruct_A() { init(); }
private:
void init()
{
ia = 0;
fa = 0.0f;
}
}
class CStruct_B : public Struct_B
{
public:
CStruct_B()
{
ib = 0;
fb = 0.0f;
static_cast<CStruct_A *>(&sA)->init();
}
}
我还有更多问题,但这可能已经太长了。
任何帮助将不胜感激。
我浏览了您引用的 "Oracle article",但在那篇文章中没有发现任何内容表明您可以按照您声称的文章描述或提供的方式初始化基础 classes任何接近您要编译的语法的示例。
C++ classes 的构造函数只能初始化其 class 的成员。它们不能直接从它们的构造函数初始化它们的 superclass 的任何成员。
话虽如此,一些编译器可能会提供它们自己的特定于编译器的语言扩展。例如,gcc 5.1 将在 -std=c++11 模式下接受以下代码:
typedef struct
{
int ia;
float fa;
} Struct_A;
class CStruct_A : public Struct_A {
public:
CStruct_A() : Struct_A({
.ia=1,
.fa=0,
})
{
}
};
但是,这非常低效并且不是标准的 C++(因为 gcc 会在 -Wpedantic
模式下警告您)。
解决您的第一个问题。从 C++ 的角度来看,这些 C 结构被认为是聚合。所以你可以这样做:
class CStruct_A : public Struct_A
{
public:
CStruct_A() : Struct_A{0, 0.0f} {};
}
这非常适合我。大括号初始化程序只是按照其成员的顺序初始化 Struct_A。
我认为处理您的第二个问题的最佳方法是将 CStruct_A 隐式转换回 Struct_A,然后使用它。
struct A {
double x;
int y;
};
class Ac : public A {
public:
Ac() : A{0.0, 1} {};
operator A() const { return A{x, y}; }
};
struct B {
B() : a(Ac()) {};
A a;
};
编辑:综上所述,我不太确定继承是解决此问题的首选。我几乎肯定宁愿从用 C++ 类 封装 C 风格的结构开始,然后从那里开始。
详细说明我将如何做到这一点:
class CStruct_A {
// ... various other code, initializes a carefully etc
public:
Struct_A * getA() { return &a; }
private:
Struct_A a;
}
现在,给出一些函数:
void func(Struct_A * var);
这样称呼它:
CStruct_A my_var();
func(my_var.getA());
它可能不像使用继承那么花哨,但它简单,有效,它允许您完全封装 C 结构并决定它们的初始化方式,编译器会保护您免于意外调用 func(myvar)等。我更喜欢这个而不是继承,除非有比你概述的更有说服力的理由使用继承。
好的...
为了结束这个问题,我想我发现初始化子结构的唯一方法几乎就是按照我在解决方法中所做的。我还没有找到另一种直接的方法。我想这没什么大不了的。我只是被原文误导了。
现在,旧代码有一个定义为 "extern" 的全局 Struct_B,我的新 C++ 程序必须分配它。为了能够使用其提升的功能,同时从旧的 C 代码角度来看仍然是 "defined",我将其声明为:
{
Struct_B *pCStrb = new CStruct_B();
...
}
所以我将它声明为旧的 c 结构,但使用 class 版本分配它。这与我最初在上面写的不同,我在上面使用 "C++" 版本来声明它。这显然是错误的,因为旧的 C 代码对名为 CStruct_B.
的结构一无所知总之...似乎正在做我想做的事,尽管不完全是 "as" 我想要的。
感谢您的帮助。