2017-05-10 6 views
1

へのポインタへのポインタから基本クラスに変換できません:ソースファイルでは、ヘッダーでは、派生クラス

class Clock : public QWidget 
{ 
    Q_OBJECT 
public: 
    explicit Clock(QWidget *parent = 0); 
...... 
} 

class ElecClock : virtual public Clock 
{ 
    Q_OBJECT 
public: 
    explicit ElecClock(QWidget *parent = 0); 
private slots: 
    void showTime(); //display two LCDNumber 
...... 
} 

class MechClock : virtual public Clock 
{ 
    Q_OBJECT 
public: 
    explicit MechClock(QWidget *parent = 0); 
...... 
} 

class NewClock : public MechClock, public ElecClock //combination of Mechclock and ElecClock 
{ 
    Q_OBJECT 
public: 
    explicit NewClock(QWidget *parent = 0); 
private slots: 
    void showTime(); //display two LCDNumber 
...... 
} 

:main.cppには

Clock::Clock(QWidget *parent) : 
    QWidget(parent) 
{ 
...... 
} 

ElecClock::ElecClock(QWidget *parent) : 
    Clock(parent) 
{ 
...... 
connect(timer, SIGNAL(timeout()), this, SLOT(showTime())); 
...... 
} 

MechClock::MechClock(QWidget *parent) : 
    Clock(parent) 
{ 
...... 
} 

NewClock::NewClock(QWidget *parent) : 
    MechClock(parent), ElecClock(parent), Clock(parent) 
{ 
...... 
connect(timer, SIGNAL(timeout()), this, SLOT(showTime())); 
...... 
} 

int main(int argc, char *argv[]) 
{ 
    QApplication a(argc, argv); 
    NewClock c; 
    c.show(); 

    return a.exec(); 
} 

私が欲しいですNewClockを表示します。しかし私がコンパイルすると、エラーは "ポインタを基本クラス 'QObject'から仮想クラス 'Clock'を介して派生クラス 'ElecClock'へのポインタに変換できません。"

エラーがmoc_ElecClock.cppで起こる:

void ElecClock::qt_static_metacall(QObject *_o, QMetaObject::Call _c,int _id, void **_a) 
{ 
    if (_c == QMetaObject::InvokeMetaMethod) { 
     ElecClock *_t = static_cast<ElecClock *>(_o); // this line 
     Q_UNUSED(_t) 
     switch (_id) { 
     case 0: _t->showTime(); break; 
     default: ; 
     } 
    } 
    Q_UNUSED(_a); 
} 

どのようにこの問題を解決するために?私のコンストラクタとスロットに何か問題はありますか? ^

答えて

1

問題は以下の接続から発生します。遅く働いているdynamic_castとして自動的に生成qt_static_metacall機能は、複数の継承の場合を中にキャストすることはできませんstatic_castを使用

私はちょうど機能への接続をカプセル化し、唯一の動的な場合は関数を呼び出すためにアドバイスできるソリューションとしてElecClock::ElecClock(QWidget *parent) : Clock(parent) { ...... ---> connect(timer, SIGNAL(timeout()), this, SLOT(showTime())); ...... }

オブジェクトの静的型は同じです。それ以外の場合は、その行を削除するか、複数の継承を拒否する必要があります。

+0

動的なオブジェクトと静的なオブジェクトの型が同じかどうかはどうすれば判断できますか? – Manhooo

+0

この場合、NewClockの接続は動作しません。タイマーでElecClockを使用する場合は、そういうことができます。 'QApplication a(argc、argv); // NewClock c; ElecClock c; c.connect(); c.show(); return a.exec(); 'ここで、connect関数は接続部分をカプセル化しています。 – ebeglary

2

static_cast次の操作を行います。キャストのためには何が必要かの計算はコンパイル時に行われるため、静的なキャストが、それは算術演算または変換をポインタで、静的と呼ばれます。

ただし、の仮想継承が存在する場合、少し難しくなります。主な問題は、仮想継承では、すべてのサブクラスがサブオブジェクトの同じインスタンスを共有することです。そのためにElecClockにはClockの代わりに ``のポインタがあり、Clockの基底クラスのオブジェクトはElecClockの外部でインスタンス化されます。

コンパイル時には、必要なポインタ演算を推論することは不可能ですが、これは、オブジェクトの実行時の型によって異なります。

ソリューション

あなたはRTTI(実行時型情報)を必要とし、キャストのためのRTTIを利用することdynamic_castの仕事です。

安全

static_cast塩基に由来する限り不変に保持するように安全です。それ以外の場合は、結果はundefined behaviorです。しかし、大規模なコードベースの広い部分に適用される不変量は、めったに保持されません。

同様のケースでstatic_castを使用する場合は、前もってassert(dynamic_cast<...>(...))を入力することを検討してください。

+0

実行時の構造体である 'dynamic_cast'は失敗することに注意してください。したがって、キャストの結果を使用する前に 'nullptr'をチェックすることを忘れないでください。 –

+0

@JesperJuhl、そうですね! –

関連する問題