Is there a way of making a base object return a derived object?

1
2
3
4
5
6
class A{
public: A *Get(){ return this; }
};

class B : public A{};


Where I would have an object B, call Get() and have it return B rather than A?
I suppose you could overload Get function like this:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
#include <iostream>
using namespace std;

class A
{
public: 
        void Get(A * result)
        {
             cout << "returning A..." << endl;
             result=this;
        }
};

class B : public A
{
public: 
        void Get(B * result)
        { 
             cout << "returning B..." << endl; 
             result=this; 
        }
};

int main()
{   
    A a, *pa;
    B b, *pb;
    
    a.Get(pa);
    b.Get(pb);
    
    cout << "hit enter to quit..." << endl;
    cin.get();
    return 0;
}

You have to pass the return value as an argument coz functions can't be overloaded depending on their return type.
Last edited on
But then again... since you have an inheritance chain you don't have to overload, just redefine Get in class B and when you call it from a B object it will override the old Get (defined in class A).
However, a new problem arises... what if you wanted to call Get for a derived object pointed to by a base pointer? You want B Get to be called but you are calling it by an A pointer...
The answer is simple, just make Get a virtual function and you're ok... (try to remove the virtual keyword to see that the last Get call returns A instead of the desired B ;) )

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
#include <iostream>
using namespace std;

class A
{
public: 
        virtual A * Get()
        {
             cout << "returning A..." << endl;
             return this;
        }
};

class B : public A
{
public: 
        //don't have to put the virtual keyword here
        //but it's a good habit (IMHO)
        virtual B * Get()         { 
             cout << "returning B..." << endl; 
             return this; 
        }
};

int main()
{   
    A a, *pa;
    B b, *pb;
    
    pa=a.Get();
    pb=b.Get();
    
    pa=&b;
    pb=(B*)pa->Get();

    cout << "hit enter to quit..." << endl;
    cin.get();
    return 0;
}
Last edited on
Curiously Recurring Template Pattern (CRTP):

1
2
3
4
5
6
7
8
9
template< typename Derived >
class Base {
  public:
      const Derived* get() const
          return this;
      }
};

class Derived : public Base< Derived > {};


But this all seems rather pointless since this is nothing more than a downcast.
Why not just downcast normally? dynamic_cast exists for this very reason:

1
2
3
4
5
6
7
8
9
10
11
12
A* a = /*whatever */;
B* b;

b = dynamic_cast<B*>(a);
if(b)
{
  // successful downcast, 'a' really did point to a 'B'
}
else
{
  // invalid downcast.  'a' did not point to a 'B'
}



Of course one would have to question why you'd need to downcast. Downcasting can often be avoided with a better design.
Last edited on
It probably is poor design on my part, I don't know how to do it better though. If anyone wants to spruce it up a bit, that would be awesome.

Purpose:
Wrapper class around ofstream that writes to file. After every line write, the file is closed, so whatever is in the stream is always committed to file rather than being lost due to unexpected escape/crash. Does a few other things as well.

This system is used by several projects(within the same solution), so I created a base type in a different file that any of the other projects can access and then derived a type tailored to each project.

The issue is outlined below.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
//Before 
class cFileObjBase
{
public:
	cFileObjBase& operator<<(const char *ch);
};

//---

class cFileObj : public cFileObjBase
{
public:
	cFileObj &operator<<( const Packet *pack );
};


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
//after
class cFileObjBase
{
public:
	virtual cFileObjBase& operator<<(const char *ch);
};

//---

class cFileObj : public cFileObjBase
{
public:
	cFileObj &operator<<( const Packet *pack );

	virtual cFileObj &operator<<(const char *ch){ cFileObjBase::operator<<(ch); return *this; }
};



Usage
1
2
3
	Packet *pack;
	cFileObj SysLog;
	SysLog << "Packet Data: "<<pack;  // < the issue is here 
Last edited on
Topic archived. No new replies allowed.