2011-06-06 29 views
4

我有以下情況。下面附上一個僞代碼。我有一個類A具有類型D或E的對象c,並且這個變化(實際上它是隨機決定的)。它使用b作爲與遠程計算機通信的消息。C++結構不同成員 - 在運行時決定

  1. 那麼,我應該如何讓結構B有不同的變量(在這種情況下,浮點數或雙精度)?
  2. 此外,當我打開一個套接字並傳輸一個對象時,對象現在將具有不同的大小。遠程計算機不知道該對象是否具有與sizeof(int)+ sizeof(float)或sizeof(int)+ sizeof(double)相對應的大小。我需要大小作爲接收數據包的參數,那麼我該如何解決這個問題?

代碼:

class C 
{ 
    ... 
}; 

class D: public C 
{ 
    ... 
}; 

class E: public C 
{ 
    ... 
}; 

struct B 
{ 
    int a; 
    // If A->c is of type D 
    float b; 
    // If A->c is of type E 
    double b; 
}; 

class A 
{ 
    B b; 
    C *c; 
    A() 
    { 
    c = (C*) new D; 
    //c = (C*) new E; 
    } 
    ... 
    ... 
    void transmit() 
    { 
    //b has some attributes depending on whether c is of type D or E 
    //Open a socket and send packets via UDP 
    //The remote host receives the packets 
    } 
}; 

我希望這說明我的問題。如果不明確或模棱兩可,請告訴我。我會提供更多細節和解釋。提前致謝。

回答

0

聯盟可以用來解決這個問題。

struct B 
{ 
    int a; 
    bool d; //d = 0 for D and 1 for E 
    union 
    { 
    float b; 
    double c; 
    } 
}; 
2

可以使用​​在運行時創建對象。

或者,使用模板:

template <class T> 
class A { 
    T a; 
} 


A<int> a = new A<int>(); 
A<double> b = new A<double>(); 

第二部分是容易的。
在你發送 - 接收協議保留4個字節開始用於sizeof(int)的...然後用sizeof(a)

+0

感謝您的答覆。你所說的將解決問題的第一部分,但不是第二部分。我需要一個適用於這兩個部件的解決方案。 – 2011-06-06 18:13:50

1

填充由於兩個d和E由C派生的實現看起來是正確的:

c = (C*) new D; 

雖然我會刪除C-Cast(不需要,如果您需要使用Cs變體)。

c = new D; 

您如何傳輸數據將取決於。但是通常你需要在部分信息中加上類型信息,這樣目的地就能理解如何解碼後面的數據流。

send(a->a); 
send("1") if a->c is D 
send("2") if a->c is E 
send(<Conditional Part>); 

作爲一個方面說明。查找智能指針。在你的類中使用一個原始指針是一個壞主意(並且不是很好的C++)。

+0

感謝您的回覆。我不能發送部分數據包,這是我的限制。我需要將它作爲單個數據包發送。任何想法我可以做到這一點? – 2011-06-06 18:22:16

1

工作的平原C++和原始套接字真是忙碌,許多最終在經過結構通過socket不假思索的其他問題上升歸因於..

  1. 你需要知道的big-endian和主機-ndian轉換
  2. 並非所有的編譯器都會像這樣處理結構體..您經常需要使用#pragma包來強制處理結構體的大小。一些編譯器不支持這一點。

如果您不擔心性能,我建議將數據作爲XML/ini內容發送,這很容易解析.INI讀者隨手可以讀取參數爲float或double。 。

如果您仍然喜歡二進制內容,我會建議學習ASN.1符號,但至少需要2周才能完全實踐您的項目,然後您將結束使用現有協議或使用您的自定義協議。

所以沒有直接的解決你的問題。除了在內存中發送結構副本外,還可以讓您的類C或D通過套接字發送序列化的數據,並將對象的類型作爲第一個字節,下一個2/4字節的數據長度,實際數據遵循休息。然後,您實現一個讀取器類,它讀取第一個字節,然後決定對象的類型,然後將調用委託給相應的類以讀取其餘數據。

+0

感謝您的回覆。但是由於我有一定的限制,我沒有選擇將數據包分成幾部分,因此我需要將它作爲單個數據包發送。有任何想法嗎? – 2011-06-06 18:23:28

1

首先,你的類層次結構看起來很可疑。從你出什麼,有BC比第三類,A,其中包含B對象和C指示器的存在相互之間沒有任何關係。然而,B中的一個變量的類型應該取決於A對象內的指針指向的哪個子類C

這似乎是不必要的耦合。爲什麼不把B的那個字段納入C的相應子類?

假設您已經搞掂你的類層次結構,你留下了希望通過套接字發送兩個不同類型的消息中的一個(大小不同)的比較直接的問題。這裏有一個解決方案:

enum message_type {type1, type2}; 

class message_type1 
{ 
    ... 
}; 

class message_type2 
{ 
    ... 
}; 

// when sending message (pseudocode) 
write message_type variable 
write message_type1 object OR message_type2 object 

// when reading message (pseudocode) 
read message_type variable 
if type1 
    read message_type1 object 
else 
    read message_type2 object 

當然,message_type1message_type2可以是相同的模板等相同的基類的子類,或者實例,以避免重複如果兩個消息類型有一些共同的東西有關。

編輯:你在其他答案的評論中提到你不能將消息拆分成不同的數據包。你能澄清這是什麼意思嗎? 「數據包」它不是一個精確的術語:TCP有,UDP和IP有數據包和以太網有。這些都不具有任何與你多少次調用send()在插座上(即兩次調用send()一定意味着兩個TCP段被髮送;反之,將一個調用send()保證您的數據將在一段中傳輸)。

+0

基本上,我有一個隊列,我推送這些數據包,並且一個線程單獨運行,從隊列中繼續傳輸這些數據包。如果我希望傳輸不同大小的數據包,那麼我需要更改代碼的其他部分,如果可以避免,我不想引起很多更改。另外,在我的系統中,通信是實時性能的障礙。調用更多發送語法會使性能變差。但是,如果沒有其他出路,那麼我將不得不做你提到的。 – 2011-06-06 19:01:04

+0

@Neel:我不確定你的意思是「調用更多的發送語法」,但讓我再說一遍,調用'send()'兩次不太可能比只調用一次額外的調用時慢包含幾個字節的數據。如果這仍然困擾你,你可以將它們連接在一個緩衝區中,然後通過一次調用將緩衝區發送到'send()'。 – HighCommander4 2011-06-08 00:05:26

+0

其實我有一個隊列,所以如果我可以將對象推入隊列,那麼我會很高興,因爲我不必在代碼中進行任何更改,否則會爲我創建許多其他問題,因爲隊列用於應用程序除了發送數據包之外。即使我將兩個緩衝區連接起來,我也無法繼續運行它,因爲接收端沒有關於連接緩衝區大小的信息。 – 2011-06-08 00:29:40