Reputation: 125
In headers:
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
......
}
In source files:
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()));
......
}
In main.cpp:
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
NewClock c;
c.show();
return a.exec();
}
I want to show the NewClock. But when i compile, the error is "cannot convert from pointer to base class 'QObject' to pointer to derived class 'ElecClock' via virtual base 'Clock'."
The error happens in 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);
}
How to solve this problem? Is there anything wrong in my constructors and slots? ^
Upvotes: 2
Views: 3752
Reputation: 84
The problem comes from connection below. As dynamic_cast
is working slower the automatically generated qt_static_metacall
function used static_cast
which is not able to cast in case of multiple inheritance
ElecClock::ElecClock(QWidget *parent) :
Clock(parent)
{
......
---> connect(timer, SIGNAL(timeout()), this, SLOT(showTime()));
......
}
As solution I just can advice to encapsulate connection into function and call the function only if dynamic and static types of object are same. Otherwise you have to remove that line or refuse from multiple inheritance.
Upvotes: 0
Reputation: 1489
static_cast
do this: a static cast is dubbed static because the computation of what is necessary for the cast is done at compile-time, be it pointer arithmetic or conversions.
However, when virtual inheritance exists things become a bit more difficult. The main issue is that with virtual inheritance all subclasses share a same instance of the subobject. In order to do that, ElecClock
will have a pointer to a ``, instead of a Clock
proper, and the Clock
base class object will be instantiated outside of ElecClock
.
Although, it's impossible at compilation time to be able to deduce the necessary pointer arithmetics. It depends on the runtime type of the object.
Solution
You need RTTI
(RunTime Type Information), and making use of RTTI for casts is the job of dynamic_cast
.
Safety
static_cast
from base to derived is safe so long as the invariant holds. Otherwise the result is undefined behavior
. However invariants enforced over wide portions of large code bases rarely stay held.
So when using static_cast
in the similar cases, consider putting assert(dynamic_cast<...>(...))
before.
Upvotes: 2