2015-09-15 18 views
5

ı C# Inherited sıralamakta istiyorum ama yapı kalıtım C# çalışmıyorC# dizme C++ yapı kalıtım

struct Base 
{ 
    USHORT size; 
} 

struct Inherited : public Base 
{ 
    BYTE type; 
} 

++ ı C aşağıdaki yapılar var diyelim. Aşağıdaki uygun mu?

public interface IBase 
{ 
    ushort Size { get; set; } 
} 

[StructLayout(LayoutKind.Sequential)] 
public struct Inherited : IBase 
{ 
    public ushort Size { get; set; } 
    public byte Type { get; set; } 
} 

Burada sorunu basitleştirilmiş ve benim yapılar yolu büyük zorluk sonuçları doğrulamak için yapım vardır. Ayrıca, yapılar, çok iyi belgelenmemiş başka bir yazılımdan geliyor ve sonuçları doğrulamak daha da zorlaştırıyor. C++ 'da miras kullanırken, çocuk yapısı öncesi veya sonrası temel sınıf alanları mı?

IBase'u, mevcut olacak temel alanları zorlamak için kullanıyorum.

Ne yazık ki, C++ tarafında denetimim yok (entegre ettiğim harici bir sistem için SDK).

+0

Sanırım temel yapının ilk olarak C++ bellek düzeninde gelmesini beklemek mantıksız değil (sanırım standart değil). Bunu denediniz mi? –

+0

@TheodorosChatzigiannakis Elbette kodu denedim ve koştum ama dediğim gibi: "[...] yapılarım, sonuçları doğrulamakta zorlanıyorlar." Bu yüzden hipotezimi doğrulamaya çalışıyorum. Girdiğin için teşekkürler! – KOTIX

+0

Muhtemelen özellikler yerine alanlar kullanıyor olmalısınız, ancak bunun işe yarayıp yaramadığını bilmiyorum. –

cevap

2

"Uygun" sözcüğü, tam olarak bu C# bildirimleri için geçerli değildir. Şimdiye kadar, kazaları önlemenin en iyi yolu, özellik ve arayüzlerin uygulama ayrıntılarına dayanarak değildir. Bu yapının bildirilmesi ve yalnızca düz alanları kullanması gerekir.

Parçacık bir hata modu göstermiyor; dolayısıyla, 'un bir sorunu olduğu gerçek beyanın basitleştirilmiş bir sürümü olduğunu varsayalım. C# kodunun yapı bildirimini doğru olarak aldığını kontrol etmenin yolu, yapının boyutunun ve son alanın ofsetinin hem C++ hem de C# 'da aynı olduğunu doğrulamaktır.

#include <Windows.h> 
#include <stddef.h> 

struct Base { 
    USHORT size; 
}; 

struct Inherited : public Base { 
    BYTE type; 
}; 


int main() 
{ 
    int len = sizeof(Inherited); 
    int ofs = offsetof(Inherited, type); 
    return 0; 
} 

Ve len ve OFS bunda değişkenleri, 4 ve 2 incelemek için ayıklayıcısını kullanın: Bu kontrol etmek biraz test programı yazarak başlayın, bu pasajı için C++ sürüm aşağıdaki gibi görünmelidir vaka. C# aynı şeyi yapın:

using System; 
using System.Runtime.InteropServices; 

class Program { 
    static void Main(string[] args) { 
     var len = Marshal.SizeOf(typeof(Inherited)); 
     var ofs = Marshal.OffsetOf(typeof(Inherited), "<Type>k__BackingField"); 
    } 
} 
public interface IBase { 
    ushort Size { get; set; } 
} 

[StructLayout(LayoutKind.Sequential)] 
public struct Inherited : IBase { 
    public ushort Size { get; set; } 
    public byte Type { get; set; } 
} 

Hala 4 ve 2, böylece mükemmel bir eş ve pinvoke iyi olmalıdır. Gerçek beyanda bir uyumsuzluk olduğunda, değişkeninde geriye doğru ilerleyin, yanlış beyan edilen üyeyi keşfedeceksiniz. Destek alanının kazık adını kontrol etmeye zorlamak için mülkün kullanılmasının sonucunu not edin. Yapı, özellik yerine alanların kullanılmasıyla bildirildiğinde bu kod çok daha az bükülecektir, kesinlikle önerilir.

1

C++ derleyicinin sınıfı sınıfta nasıl düzenleyeceğine dair varsayımlarda bulunuyorsunuz. Derleyicinize bağlı olarak & hangi bayrakları kullanıyorsunuz, bu değişebilir. Ayrıca kullandığınız alanlara bağlı olarak. Örneğin, bazı derleyiciler böyle bir nesne hizalamak mükemmel makul olacaktır:

struct Obj 
{ 
    char c; // <-- starts at 0 byte 
    int i; // <-- starts at 4 byte - 4 byte alignment improves performance. 
} 

Yani C++ sınıflar C# ölçümler almasını beklediğiniz nasıl eşleme olmayabilir görebilirsiniz.

Bunu denetlemek için bayraklar vardır - paketi C++ olarak 0 olarak ayarlayabilir, ardından C# 'da sıralı düzeni kullanabilirsiniz ve ardından yaklaşımınız makul olacaktır.

Özelliklerin kullanımınız önemli bir sorun değildir - önemli olduğunu düşündüğünüz sürece - burada örtük destek alanı derleyici tarafından sizin için nasıl oluşturulacaktır.

0

Sonunda yapmaya çalıştığım şeyin gerçek sayısını buldum. Kullanmakta olduğum SDK'dan gelen geri bildirim, struct Base'u gönderir ve içindeki alanları analiz ederek hangi devralınan türün olduğunu belirler. Sonra temel türünü devralınan türüne "dökmek zorundayım".

static T CopyStruct<T>(ref object s1) 
{ 
    GCHandle handle = GCHandle.Alloc(s1, GCHandleType.Pinned); 
    T typedStruct = (T)Marshal.PtrToStructure(handle.AddrOfPinnedObject(), typeof(T)); 
    handle.Free(); 
    return typedStruct; 
} 

o struct Base büyüklüğüne dışına çıkmak asla yapmanın Bu şekilde: İşte başlangıçta yaptığını budur. Bu nedenle, Inherited türünün tüm ek alanları doğru şekilde başlatılamaz (kopyalanan belleğin dışında okuma). Ben aşağıdaki gibi güvensiz bir şekilde tekrar yaptık:

fixed (Base* basePtr= &base) 
{ 
    inherited= *(Inherited*) basePtr; 
} 

Bu şekilde, inherited puan orijinal bellek bloğuna ve base boyutu dışında okuyabilirsiniz.

Tüm önceki cevaplarınız için teşekkürler! Aslında sahip olduğum tüm C++ modellerinin boyutlarını ve ofsetlerini doğrulamak için bir C++ uygulaması oluşturdum.