2012-01-12 70 views
1

我有以下程序:C++初始化程序列表與工會,爲什麼不同的結果?

#include <initializer_list> 
#include <iostream> 

class A; 
class nih { 
public: 
    virtual void apply(A & a) const { std::cout << "generic" << std::endl; }; 
}; 

union niit; 
class A { 
public: 
    int s; char kau; 
    A() : s(1), kau('-') { } 
    A(std::initializer_list<niit> k); 
}; 

class sn : public nih { int s; public: sn(int x) : s(x) { } 
    virtual void apply(A & a) const { a.s=s; } }; 
class kaun : public nih { char kau; public: kaun(char x) : kau(x) { } 
    virtual void apply(A & a) const { a.kau=kau; } }; 
union niit { sn sni; kaun kauni; nih nihi; 
    niit(const sn & s) : sni(s) { } 
    niit(const kaun & k) : kauni(k) { } 
}; 

A::A(std::initializer_list<niit> k) { 
    const niit *n=k.begin(); 
    for(int i=0;i<k.size();i++) { 
    const nih* p=&n[i].nihi; 
    p->apply(*this); 
    } 
} 

int main(int argc, char**argv) { 
    A r {kaun('a'),sn(91)}; 
    std::cout << r.s << r.kau << std::endl; 
} 

我得到預期的結果,這是91a。不過,如果我更改線路

p->apply(*this); 

以下幾點:

((const nih*)(&n[i].nihi))->apply(*this); 

這應該是置換同等價值,它不再起作用,而是它打印:

generic 
generic 
0 

也就是說,它執行nih的通用方法。這是爲什麼?我試過gcc 4.6,選項-std=c++0x,以防萬一。

回答

2

聯合只能與POD類型一起使用,因此不能具有虛函數或非平凡構造函數/析構函數的成員,所以這是未定義的行爲。讀(從this answer截取)的標準的§9.5.1:

甲聯合可以有成員函數(包括構造器和析構函數 ),但不虛函數。一個工會不應該有基地 類。聯盟不得用作基礎類。具有非平凡構造函數,非平凡複製構造函數,非平凡析構函數或非平凡複製賦值運算符 的 類的對象不能是聯合成員,也不能是數組這樣的對象。如果一個 聯合包含一個靜態數據成員或一個引用類型的成員 該程序是格式不正確的。

而且

在某些情況下,C++允許使用僅POD類型。例如,對於 示例,C++中的聯合不能包含具有虛擬 函數或非平凡構造函數或析構函數的類。這個限制 是強加的,因爲編譯器無法知道應該爲聯合調用哪個構造函數或 析構函數。

+0

是不是C++ 03? IIRC,C++ 11允許使用非平凡的ctor和dtor類型。 – Xeo 2012-01-12 15:56:16

+0

這個限制似乎不再存在於C++ 11中。如果沒有-std = C++ 0x標誌,Gcc根本不編譯代碼,抱怨帶有構造函數的類不被允許。有了旗幟,它甚至不會給出警告。 – 2012-01-12 16:01:49

+0

@Xeo,Juho Ah,然後只考慮這個答案C++ 03。在C++ 11中,它是否也允許您與具有虛擬功能的成員進行聯盟? – 2012-01-12 16:03:08