views:

89

answers:

5

I am wondering if it is possible to call a derived class´ function from within a function called by the base constructor (shouldn´t it already be created when the code in the brackets are executed?)

#pragma once
class ClassA
{
public:
 ClassA(void);
 virtual ~ClassA(void);

 void Init();

protected:
 short m_a;
 short m_b;

 virtual void SetNumbers(short s);
};

include "ClassA.h"
#include <iostream>


ClassA::ClassA(void) : m_a(0), m_b(0)
{
Init();
}


ClassA::~ClassA(void)
{
}

void ClassA::SetNumbers(short s)
{
 std::cout << "In ClassA::SetNumbers()\n";
 m_a = s;
 m_b = s;
}

void ClassA::Init()
{
 this->SetNumbers(2);
}

#pragma once
#include "ClassA.h"
class ClassB : public ClassA
{
public:
 ClassB(void);
 virtual ~ClassB(void);

 virtual void SetNumbers(short);

 int x;
};

#include "ClassB.h"
#include <iostream>


ClassB::ClassB(void)
{
}


ClassB::~ClassB(void)
{
}

void ClassB::SetNumbers(short s)
{
 std::cout << "In ClassB::SetNumbers()\n";

 m_a = ++s;
 m_b = s;

 ClassA::SetNumbers(s);
}

Any suggestions how to do it?...

Thank You in advance :)...

+2  A: 

You can't do this for the simple logical reason that while the base class is being constructed, the derived class hasn't even begun to be constructed. You can't call a member function on an object that doesn't exist (yet).

In practice, even if you managed to call SetNumbers and assign to the member variables of the derived class before they were initialized they would surely be overwritten when they finally get initialized. I admit it's a bit pointless to reason about this as we would be well outside defined behaivour.

Charles Bailey
+2  A: 

No. All parts of B (starting with A, as it's base) are constructed before B's constructor is called. So, by the time SetNumbers is called, no part of B (except for the A part) has been constructed --- and that may include the v-table, so there's no way to know where that call is going to go.

Of course, there is a simple solution to this: Call B::SetNumber() from within B's constructor (That is, after all, the purpose of B's constructor)

James Curran
well... this is just an simple example for a server program i was writing... but i guess i have to rethink the automatic call of Init()...
Incubbus
@Incubbus: A lot of people who ask that question come from languages, like ObjectiveC, which don't have ctors, and where the idiom you describe in the norm -- and wonder why the idiom is broken in C++.
James Curran
+1  A: 

No, sorry. :( It might compile in one or two C++ compilers, but it's not recommended. From the C++ FAQ Lite section 10.7:

[10.7] Should you use the this pointer in the constructor?

[...snip...]

Here is something that never works: the {body} of a constructor (or a function called from the constructor) cannot get down to a derived class by calling a virtual member function that is overridden in the derived class. If your goal was to get to the overridden function in the derived class, you won't get what you want. Note that you won't get to the override in the derived class independent of how you call the virtual member function: explicitly using the this pointer (e.g., this->method()), implicitly using the this pointer (e.g., method()), or even calling some other function that calls the virtual member function on your this object. The bottom line is this: even if the caller is constructing an object of a derived class, during the constructor of the base class, your object is not yet of that derived class. You have been warned.

NOTE: Emphasis mine.

More details at the link

The Alchemist
A: 

A simple design solution is to use aggregation instead of inheritance.

Nikolai N Fetissov
That would merely make what he is doing impossible. It would, however, not solve his problem (since his design is based on inheritance)
James Curran
That's why I'm saying it's a *design* alternative.
Nikolai N Fetissov
Besides, what he's trying to do is impossible anyway.
Nikolai N Fetissov
His current design compiles, but fails at run-time. Your solution merely makes it fail at compile time. However, except for this one hurdle, his overall task is suited for inheritance. Changing the entire design to aggregation, just to solve this problem is pointless extra work.
James Curran
My solution is to avoid inheritance if possible, and *never* use `protected` data members. I think we are arguing about different things.
Nikolai N Fetissov
+1  A: 

The only time you can do this is when something is derived from a template that is parameterised by itself:

template<typename T> class base
{
  T* down_cast() throw()
  {
    return static_cast<Derived*>(this);
  }
  const T* down_cast() const throw()
  {
    return static_cast<const Derived*>(this);
  }
public:
  base()
  {
    down_cast()->doSomething();
  }
 /* … */
};

class derived : private base<derived>
{
public:
  void doSomething()
  {
  }
};

Note that doSomething is public and not virtual.

We can static_cast to derived, because it's known that derived is the derived type.

Deriving something from a base parameterised by itself is a strange thing to be doing at the best of times. It's said that when the ATL team in microsoft used it they asked the C++ compiler team if it was valid and nobody was sure, though it is valid because template construction depends on names as follows:

First the template is available, but not used in a class. Then, the name derived available. Then it instantiates the layout of base<derived> — this requires knowledge of the member variables and virtual functions, as long as none of that depends upon knowledge of derived’s layout (pointers and references are fine) this will all go okay. Then it will create the layout of derived, and finally it will create derived’s member functions, which may include creating member functions for base<derived>. So as long as base<derived> doesn’t contain a derived member variable (base classes can never contain a member variable of a type derived from themselves) or a virtual function that requires knowledge of derived’s layout we can indeed do the dicey-looking piece of inheritance above.

This includes being able to call non-virtual public members of derived from base during construction, because it's already part of base. There are strong limitations on this. In particular, if doSomething() depends on anything constructed in derived's constructor it won't work as derived hasn't been constructed yet.

Now, is this actually a good idea? No.

Jon Hanna