I have classes A1, A2, B, and C. A2 inherits from A1. C inherits from A2 and B, and its constructor initializes all B, A2, and A1 variables.

As a tree, it looks like this:

C
 / \
B   A2
    |
    A1

I have a function Foo that takes a parameter pointer P of type B*, but the only parameters passed will be of type C* (and thus their objects will have all B, A2, and A1 variables initialized)

Inside Foo, I can type cast my P into A2* or A1* pointers, and I'm able to use those functions. The A2 and A1 functions run without complaining, but none of the A2 or A1 variables get recognized (when I debug they're all uninitialized), which leads to bugs.

Can somebody explain why this happens and what I can do to fix it (I can't change Foo's parameter type), or direct me to a source where I can read more about it?

EDIT: when I say I'm explicitly casting my P into A2*, I mean I just do (A2*)P->bar(), so I may be using the wrong type of casting.

Recommended Answers

All 5 Replies

It's hard to say without seeing your code, but I'd wager your cast is wrong. Compare your code with this skeleton and tell me if you're doing something equivalent:

#include <iostream>

class A1 {
public:
    int a1;
    virtual ~A1() {}
};

class A2: public A1 {
public:
    int a2;
    virtual ~A2() {}
};

class B {
public:
    int b;
    virtual ~B() {}
};

class C: public A2, public B {
public:
    int c;
};

void foo ( B* p )
{
    C *cp = dynamic_cast<C*> ( p );

    if ( cp != 0 ) {
        std::cout<< cp->a1 <<'\n'
                 << cp->a2 <<'\n'
                 << cp->b <<'\n'
                 << cp->c <<'\n';
    }
}

int main()
{
    C c;

    c.a1 = 1;
    c.a2 = 2;
    c.b = 3;
    c.c = 4;

    foo ( &c );
}

Unfortunately this code is for a proprietary application and the classes span several files, so the full code would be impractical to put up.

I was only using explicit type casting, but I started to use dynamic_cast, though it's returning type void*.

Also, I screwed up when I was describing my problem. Class B has a function Foo(), but it will only be used by objects type C. Inside Foo(), we attempt to cast the keyword this, so it's something like this:

...
class B
{
  void Foo()
  {
    C* thisC = dynamic_cast<C*>(this); //returns type VOID*  
  }
}
...

>Also, I screwed up when I was describing my problem.
Nice. How about you give me a bare bones example of your code, similar to the one I gave you. At least that way I'll have a better idea of what your hierarchy looks like.

ok, that was a good idea. I was able to narrow the problem down by creating a bare-bones example (took so long because I was hoping to find a fix myself):

stafx.h

#pragma once


#include <iostream>
#include <tchar.h>

class A1
{
  int a1var;
public:
  A1() {};
  int getvar() { return a1var; };
  void setvar(int n) { a1var = n; };
};

class A2 : public A1
{
  public:
  A2() : A1() {setvar(5);};
};

class B
{
public:
  B() {};
  void Foo (int n);
  virtual Bar() {}; // dummy function to make this a polymorphic class
};

class C : public A2, public B
{
public:
  C() : A2() , B() {};
};

InheritanceTest.cpp:

#include "stdafx.h"

using namespace std;

void B::Foo (int n) 
{
  cout << (n==((C*)this)->getvar()) ? 1 : 0;
  cout << endl;
  cout << (n==((A2*)this)->getvar()) ? 1 : 0;
};

int _tmain(int argc, _TCHAR* argv[])
{
  C cVar = C();
  cVar.Foo(5);
	return 0;
}

I had to split the function definition for B because it complained of referencing the non-yet-existent class C.

The output produced by cVar.Foo(5) is "1 \n 0", when I want it to be "1 \n 1". Casting inside B to (C*)this seems to preserve everything because it "casts up", but casting to (A2*)this messes up because it "casts across". I verified this in my real project and casting up did indeed preserve the object variables, while casting across no longer recognized their values.

In my real project, I'll need to cast across.

C-style casts are incorrect in that case: class B is_NOT_a C, A1 or A2.

It's impossible to use this construct in the definition of parent of C:

class B {
    ...
    void foo()
    {
        C* p = dynamyc_cast<C*>(this);
        ...
    }
    ...
};

Class B do not know its descendants. Incomplete C declaration can't help in that case (C* type var is invalid target type for dynamic_cast with incomplete declaration of C). However you can place B::foo() implementation after definition of C (what's a strange inheritance: the parent must know its descendant).

This sceleton works fine:

class A1 {
public:
    A1():i(1001) {}
    virtual ~A1() {}
    virtual char const* who() const { return "A1"; }
protected:
    int i;
};
class A2: public A1 {
public:
    A2():A1(),i(1002) {}
    char const* who() const { return "A2"; }
protected:
    int i;
};

class B {
public: // must be polymorphic!
    virtual ~B() {}
    void foo() {
        C* pc = dynamic_cast<C*>(this);
    }
};
class C: public A2, public B {
public:
    C() { A1::i = 1; A2::i = 2; }
    char const* who() const { return "C"; }
    void show() const {
        cout << A1::i << ':' << A2::i;
    }
};
void foo(const B* p)
{
    const C* pc;
    pc = dynamic_cast<const C*>(p);
    if (pc) {
        cout << pc->who() << '\t';
        pc->show();
        cout << endl;
        const A1* pa1 = pc;
        cout << pa1->who() << endl;
    } else
        cout << "Don\'t know\n";
}

int main()
{
    C c;
    c.show(); cout << '\n';
    foo(&c);
    return 0;
}
Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.