How to determine base class direct or not?

Hi all!

Can anybody help me with following problem. I have such code:
class B {
public:
   virtual void b(){}
   double b_field;
};

struct D : B {
   virtual void fr(){}
};

class C {
public:
   virtual void C_f(){}
};

class A : public C,
           public virtual D {
public:
   int a_field;
   virtual void a(){}
};
class A1 : public C, public B,
           public virtual D {
public:
   int a_field;
   virtual void a(){}
};

I write function that determines "Has class and his bases a common base?".
For example for class A this function returns false and for class A1 - true. In A1 as you can see B is base class for A1 and for D.
I tried to use isDerivedFrom(), but this function searches path from A to B(path is A->D->B) and if path exists return true.
I need something like isDirectDerivedFrom.

So my question is, what is the best way to determine these relations?

  - Dmitry.

You're trying to ask whether a type is directly named by one
of the base specifiers? I don't think we have a utility function
for that, but you can just walk the class's base specifiers directly.

John.

Yes, you are right.
Now I have such code:
for (CXXRecordDecl::base_class_const_iterator I = RD->bases_begin(),
        E = RD->bases_end(); I!= E; ++I) {
     const CXXRecordDecl *Base = I->getType()->getAsCXXRecordDecl();

     for (CXXRecordDecl::base_class_const_iterator IB = Base->bases_begin(),
          EB = Base->bases_end(); IB != EB; ++IB) {

       for (CXXRecordDecl::base_class_const_iterator II = RD->bases_begin(),
            EE = RD->bases_end(); II != EE; ++II) {

         if (IB->getType()->getAsCXXRecordDecl() ==
             II->getType()->getAsCXXRecordDecl())
           return true;
       }
     }
   }
I think it is not good approach, but I can`t think of alternatives.

  - Dmitry.

You could iterate over each of RD's bases and check whether there
are multiple paths from RD to the base.

I'm curious what this is for. Just a warning about having redundant
copies of a base class? The easiest algorithm would probably be
to do a search of the hierarchy and track what classes you find.

John.

This information is need to implement RTTI Class Hierarchy Descriptor in MS ABI.
This struct has following fields:
struct RTTIClassHierarchyDescriptor
{
     DWORD signature; //always zero?
     DWORD attributes; //bit 0 set = multiple inheritance, bit 1 set = virtual inheritance
     DWORD numBaseClasses; //number of classes in pBaseClassArray
     struct RTTIBaseClassArray* pBaseClassArray;
};
Yesterday I discovered that third bit(bit 2) in attributes field set when we have class like A1.
If you need more information about it you can see this link http://www.openrce.org/articles/full_view/23 .

  - Dmitry.

Aha. I would guess that this bit indicates whether the object has any public ambiguous base-class subobjects; if it does, the dynamic_cast algorithm can't just stop at the first such subobject it finds, it has to keep searching to see if the cast fails due to ambiguity. You should definitely be doing this as a walk over the class hierarchy. Pseudocode:

  queue : list<class>
  visited : set<class>
  visitedVirtual : set<class>

  queue.insert(mostDerived)
  while derived = queue.pop():
    foreach base in derived.bases:
      next unless base.public
      next if base.virtual and visitedVirtual.insertAndContains(base.class)
      return true if visited.insertAndContains(base.class)
      queue.insert(base.class)
  return false

John.

This information is need to implement RTTI Class Hierarchy Descriptor in MS ABI.
This struct has following fields:
struct RTTIClassHierarchyDescriptor
{
    DWORD signature; //always zero?
    DWORD attributes; //bit 0 set = multiple inheritance, bit 1 set = virtual inheritance
    DWORD numBaseClasses; //number of classes in pBaseClassArray
    struct RTTIBaseClassArray* pBaseClassArray;
};
Yesterday I discovered that third bit(bit 2) in attributes field set when we have class like A1.

Aha. I would guess that this bit indicates whether the object has any public ambiguous base-class subobjects; if it does, the dynamic_cast algorithm can't just stop at the first such subobject it finds, it has to keep searching to see if the cast fails due to ambiguity. You should definitely be doing this as a walk over the class hierarchy. Pseudocode:

Yes, you are right.

   queue : list<class>
   visited : set<class>
   visitedVirtual : set<class>

   queue.insert(mostDerived)
   while derived = queue.pop():
     foreach base in derived.bases:
       next unless base.public
       next if base.virtual and visitedVirtual.insertAndContains(base.class)
       return true if visited.insertAndContains(base.class)
       queue.insert(base.class)
   return false

John.

Thanks for pseudocode, it works fine. But we don`t need to check that base is public or not. This bit sets also for private and protected bases.

  - Dmitry.

Interesting, okay.

John.