class Base{ virtual bool IsComposite(){return false}; };
class Single:public Base{};
class Multi:public Base{virtual bool IsComposite(){ return true; }};
class Base{ bool IsComposite; Base():IsComposite(false){} };
class Single : public Base{};
class Multi : public Base{Multi():IsComposite(true){}};
class Base {virtual const bool IsComposite=false;}; //vtable contains value false
class Single : public Base{}; //vtable contains value false
class Multi : public Base { virtual const bool IsComposite=true;}; //vtable contains value true
...
{
Base*b= new Derived;
b->IsComposite; //false
Base*m= new Multi;
m->IsComposite; //true
Base::IsComposite;//false
}
virtual int dataMember1(2);
virtual int dataMember2{3};
virtual int dataMember3 = 4; //Not legal.
The fact is that people roll their own RTTI for speed, and this is usually how it's implemented, and they do that because they need the absolutely maximum performance.
- Why are they being initialized in the constructor? Do I really need to construct an instance for them to be initialized? And can the initialization depend on constructor parameters? If they're static, at least treat them the same as other static members.
Extending the introspective capacity of C++ wouldn't solve the same problem. We already have the capacity to get this kind of value- the problem is that the native implementation is too slow for a number of reasons.
Last I checked, changing the language so that the current RTTI can be performance-competitive would effectively result in modules, or possibly something even more extreme in terms of changing the language- i.e., it's effectively an unfixable problem. The reason why the existing RTTI is so slow is basically because all inheritance hierarchies are arbitrarily complex, from the point of view of the runtime, whereas Clang can do something much cheaper, since it knows that, say, nobody inherits from llvm::Function- whereas the compiler does not know such a thing.
Last I checked, changing the language so that the current RTTI can be performance-competitive would effectively result in modules, or possibly something even more extreme in terms of changing the language- i.e., it's effectively an unfixable problem. The reason why the existing RTTI is so slow is basically because all inheritance hierarchies are arbitrarily complex, from the point of view of the runtime, whereas Clang can do something much cheaper, since it knows that, say, nobody inherits from llvm::Function- whereas the compiler does not know such a thing.
On Thursday, January 24, 2013 10:20:44 PM UTC+1, DeadMG wrote:Last I checked, changing the language so that the current RTTI can be performance-competitive would effectively result in modules, or possibly something even more extreme in terms of changing the language- i.e., it's effectively an unfixable problem. The reason why the existing RTTI is so slow is basically because all inheritance hierarchies are arbitrarily complex, from the point of view of the runtime, whereas Clang can do something much cheaper, since it knows that, say, nobody inherits from llvm::Function- whereas the compiler does not know such a thing.We're not dealing with inheritance structures. What's slow is dynamic_cast, not typeid.
OK, but before we solve a problem, let's analyze why dynamic_cast is slow to begin with. What exactly is it about this feature that [i]requires[/i] that it be slow, and why would this "virtual data" be somehow faster? Isn't there a way to implement dynamic_cast so that it could just automatically generate and use this data?
struct GCObject {
virtual ~GCObject() {}
};
struct Derived : public GCObject {
static size_t numObjectsOfType_;
static SharedInfo* shared_;
Derived() {
if (numObjectsOfType_++ == 0)
shared_ = newSharedInfo();
...
}
virtual ~Derived() {
if (--numObjectsOfType_ == 0)
delete shared_;
}
};
void sweepObject(GCObject* o) {
o->~GCObject();
}
struct GCObject {
virtual static size_t numObjectsOfType_;
virtual static void freeShared() {}
~GCObject() {} // non-virtual
};
struct Derived : public GCObject {
static ShareInfo* shared_;
virtual static freeShared() {
delete shared_;
}
Derived() : GCObject() {
if (numObjectsOfType_++ == 0)
shared_ = newSharedInfo();
}
};
void sweepObject(GCObject* o) {
if (--o->numObjectsOfType_ == 0)
o->freeShared();
}
virtual static freeShared() {
delete shared_;
}
class Base
{
public:
virtual static const bool IsSerializable=true; //each subclass advertises serializability
virtual static size_t CreationCount=0; //each subclass can count the number of instances created
Base() { ++CreationCount;}//Increments Base::CreationCount
void DynamicIncrement()
{ ++CreationCount; } // Increments ThisClass::CreationCount as chosen by the dynamic type of this
};
class Special : public Base
{
public:
virtual static const bool IsSerializable=false; //this class cannot be serialized.
Special() { ++CreationCount; } //Increments Special::CreationCount
};
int main()
{
Base::CreationCount; // =0
Base* b = new Base;
Base::CreationCount; //=1
b->CreationCount; // = 1, accesses static Base::CreationCount
b->IsSerializable; // =true, accesses static const Base::IsSerializable
Base* s = new Special;
Base::CreationCount; //=2. Was incremented in Base::Base
s->CreationCount; // =1, accesses static Special::CreationCount
s->IsSerializable; //=false, accesses static const Special::IsSerializable
}
> 2013/1/25 Richard Smith
>> Given:
>>
>> struct A {
>> virtual static const int x = 0;
>> };
>> struct B : A {
>> };
>>
>> Do we need a definition, "const int A::x;", if we odr-use A::x?
>> Do we need a definition if we don't odr-use A::x? (Are all virtual
>> static data members odr-used in the same way that all virtual
>> functions are?)
>> Do we have &A::x == &B::x?
>>
>> (I think the answers should be: yes, yes, and yes.)