将C风格的结构与C ++混合

时间:2015-10-08 01:32:08

标签: c++ c struct mixing

我没有C ++的期望,因为你无疑会注意到。但是我试图升级"一些旧的C代码到C ++。在这个过程中,我试图将旧结构推广到类。我发现了这篇关于我试图做的一些事情的Oracle文章。

http://www.oracle.com/technetwork/articles/servers-storage-dev/mixingcandcpluspluscode-305840.html

但有两件事。这篇文章并没有解决我遇到的更复杂的案例。而我的"解决方法"似乎没有导致一致的结果。所以我在这里详细介绍一下。

旧C风格结构:

typedef struct
{
    int ia;
    float fa;
    ...
} Struct_A;

typedef struct
{
    Struct_A sA;
    int ib;
    float fb;
    ...
} Struct_B;

C ++
根据Oracle文章,我应该能够将Struct_A提升为类,并且仍然能够使用具有旧C函数的类版本。这显然是如何:

class CStruct_A : public Struct_A  // Inherits from C- Struct_A
{
public:
    CStruct_A() : ia(0), fa(0.0f) {}
}

暂停。就在这里,我已经有了一个问题。我似乎无法按照文章中的说明初始化C-Structure元素,如上所示。编译器不接受它。我必须重写这个课:

class CStruct_A : public Struct_A
{
public:
    CStruct_A()
    {
        ia = 0;
        fa = 0.0f;
    }
}

这是第一个问号。这不是一个大问题,但文章声称可以做到。

接下来,更棘手的问题。提升Struct_B,其中包含Struct_A成员。我想确保使用A类的构造函数来初始化变量。但我不确定如何强迫它。在我的c ++代码中,如果我有类似的东西:

{
    CStruct_B *pCStrb = new CStruct_B();
    ...
}

B类的构造函数被调用但不是A类。我的解决方法很蹩脚......但这是我现在唯一可以解决的问题。我在类A中声明了一个内部私有函数ini(),使类B成为朋友并从类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();
    }
}

我有更多问题,但这可能已经太久了。

任何帮助将不胜感激。

3 个答案:

答案 0 :(得分:1)

我已经浏览了您引用的“Oracle文章”,我在该文章中找不到任何暗示您可以按照您声明文章描述的方式初始化基类,或者给出一个示例,其中包含任何靠近你试图编译的语法。

C ++类的构造函数只能初始化其类的成员。他们不能直接从他们的构造函数初始化他们的超类的任何成员。

话虽如此,一些编译器可能会提供自己的编译器特定的语言扩展。例如,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模式下警告你)。

答案 1 :(得分:0)

...好的

要结束这个问题,我想我发现初始化子结构的唯一方法就是在我的解决方法中做的事情。我没有找到另一种直接的方式。我想这不是什么大不了的事。我只是被原始文章误导了。

现在,旧代码的全局Struct_B定义为“extern”,我的新c ++程序必须分配它。为了能够使用其提升的功能,同时仍然从旧的C代码角度“定义”,我将其声明为:

{
    Struct_B *pCStrb = new CStruct_B();
    ...
}

所以我将它声明为旧的c结构,但是将它与类版本一起分配。这与我上面最初编写的内容不同,我使用“C ++”版本来声明它。这显然是错误的,因为旧的C代码对CStruct_B的结构一无所知。

无论如何......似乎正在做我想做的事情,虽然不完全是“我想要的”。

感谢您的帮助。

答案 2 :(得分:-1)

解决您的第一个问题。从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)等除了有一个比你概述的继承更有说服力的理由之外,我更喜欢这种继承。