C++ 是否可以在C++;在C代码中使用指向结构的指针?

C++ 是否可以在C++;在C代码中使用指向结构的指针?,c++,c,gcc,extern-c,C++,C,Gcc,Extern C,这样做是否有副作用: C代码: struct foo { int k; }; int ret_foo(const struct foo* f){ return f.k; } C++代码: class bar : public foo { int my_bar() { return ret_foo( (foo)this ); } }; < C++代码周围有一个外部“C”,每个代码都在自己的编译单元内。 这是跨编译器移植的吗?哇,这太糟

这样做是否有副作用:

C代码:

struct foo {
      int k;
};

int ret_foo(const struct foo* f){ 
    return f.k; 
}
C++代码:

class bar : public foo {

   int my_bar() { 
       return ret_foo( (foo)this ); 
   }

};
< C++代码周围有一个<代码>外部“C”<代码>,每个代码都在自己的编译单元内。

这是跨编译器移植的吗?

哇,这太糟糕了

这是跨编译器移植的吗

绝对不是。考虑以下事项:

foo* x = new bar();
delete x;
为了让它工作,foo的析构函数必须是虚拟的,而它显然不是。不过,只要您不使用
new
,并且只要派生的objectd没有自定义析构函数,您就可以幸运了


/编辑:另一方面,如果代码仅用于问题中,那么继承与组合没有任何优势。只需遵循m_pGladiator给出的建议。

我当然不建议使用这种奇怪的子类。最好将您的设计更改为使用组合而不是继承。 只加入一名成员

foo*m_pfoo

在酒吧里,它会做同样的工作


您可以做的另一件事是再制作一个类FooWrapper,用相应的getter方法包含结构本身。然后您可以对包装器进行子类化。这样,虚拟析构函数的问题就消失了。

我认为这不一定是个问题。行为是很好定义的,只要你对生命问题小心(不要混合和匹配C++和C代码之间的分配),你就会做你想做的事情。它应该在编译器之间完全可移植


析构函数的问题是真实的,但在基类析构函数不是虚拟的任何时候都适用,而不仅仅适用于C结构。这是您需要注意的,但并不排除使用此模式。

它可以工作,并且可以移植,但您不能使用任何虚拟函数(包括析构函数)

我建议您不要这样做,而是使用包含Foo的Bar

class Bar
{
private:
   Foo  mFoo;
};

我不明白为什么不简单地将ret_foo作为成员方法。您当前的方式使您的代码非常难以理解。首先使用一个带有成员变量和get/set方法的实类有什么困难


我知道在C++中可以对结构进行子类化,但危险在于其他人不能理解你编码的内容,因为很少有人真正去做。我会选择一个健壮的通用解决方案。

它可能会起作用,但我不相信它一定会起作用。以下是ISO C++ 10/5的引用:

基类子对象的布局(3.7)可能与同一类型的最派生对象的布局不同

很难想象在“现实世界”中会出现这种情况

编辑:

底线是,该标准没有限制基类子对象布局可以不同于具有相同基类的具体对象的位置数量。结果是,对于基类子对象,您可能拥有的任何假设(如POD ness等)都不一定正确

编辑:

另一种方法是将“foo”设为“bar”的成员,并在必要时提供一个转换运算符,这是一种行为定义明确的方法

class bar {
public:    
   int my_bar() { 
       return ret_foo( foo_ ); 
   }

   // 
   // This allows a 'bar' to be used where a 'foo' is expected
   inline operator foo& () {
     return foo_;
   }

private:    
  foo foo_;
};
“永远不要从具体的类派生。”-萨特

“使非叶类抽象化。”-迈尔斯

对非接口类进行子类划分是错误的。你应该重构你的库


从技术上讲,您可以做您想做的事情,只要您不调用未定义的行为。g、 ,通过指向其基类子对象的指针删除指向派生类的指针。对于C++代码,你甚至不需要<代码>外部“C”<代码>。是的,它是便携式的。但是它的设计很差。

这是完全合法的,尽管它可能会让其他程序员感到困惑

您可以使用继承来使用方法和构造函数扩展C结构

样本:

struct POINT { int x, y; }
class CPoint : POINT
{
public:
    CPoint( int x_, int y_ ) { x = x_; y = y_; }

    const CPoint& operator+=( const POINT& op2 )
    { x += op2.x; y += op2.y; return *this; }

    // etc.
};

扩展结构可能“更”邪恶,但不是禁止您做的事情。

这是完全合法的,您可以在MFC CRect和CPoint类的实践中看到这一点。CPoint源于POINT(在windef.h中定义),而CRect源于RECT。您只是用成员函数装饰对象。只要不使用更多数据扩展对象,就可以了。事实上,如果您有一个复杂的C结构,默认初始化很困难,那么用一个包含默认构造函数的类来扩展它是解决这个问题的一种简单方法

即使您这样做:

foo *pFoo = new bar;
delete pFoo;
那么您就没事了,因为您的构造函数和析构函数都很简单,而且您还没有分配任何额外的内存


你也不必用“Extn”C“”来包装C++对象,因为实际上你并没有把C++类型传递给C函数。

< P>这是完全合法的。在C++中,类和结构是相同的概念,除了默认所有结构成员都是公共的。这是唯一的区别。因此,询问是否可以扩展结构与询问是否可以扩展类没有什么不同

这里有一个警告。不能保证编译器之间的布局一致性。因此,如果用C++编译器编译C代码,则可能会遇到与成员布局有关的问题(特别是填充)。当使用同一个供应商的C和C++编译器时,甚至会发生这种情况。 我在gcc和g++中遇到过这种情况。我在一个使用了几个大型结构的项目上工作。不幸的是,G++打包的结构比GCC明显宽松,这导致了C和C++代码之间共享对象的重大问题。我们最终不得不手动设置填充和插入填充,使C和C++代码对结构进行同样的处理。但是,请注意,无论子类是什么,都可能发生此问题。事实上,在本例中,我们没有对C结构进行子类化。

但这不是