Как вызвать метод производного класса из метода базового класса в конструкторе base - PullRequest
0 голосов
/ 18 августа 2010

Мне интересно, можно ли вызвать функцию производного класса из функции, вызываемой базовым конструктором (разве она не должна быть создана при выполнении кода в скобках?)

#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);
}

Есть предложения, как это сделать? ...

Заранее спасибо:) ...

Ответы [ 5 ]

2 голосов
/ 18 августа 2010

Нет.Все части B (начиная с A, как его основания) создаются до вызова конструктора B.Таким образом, к тому времени, когда вызывается SetNumbers, ни одна часть B (кроме части A) не была построена - и это может включать v-таблицу, так что нет способа узнать, куда будет идти этот вызов.

Конечно, есть простое решение для этого: вызов B :: SetNumber () из конструктора B (это, в конце концов, цель конструктора B)

2 голосов
/ 18 августа 2010

Вы не можете сделать это по простой логической причине: во время создания базового класса производный класс даже не начал создаваться.Вы не можете вызывать функцию-член для объекта, который еще не существует.

На практике, даже если вам удалось вызвать SetNumbers и назначить переменные-члены производного класса до того, как онибыли инициализированы, они наверняка будут перезаписаны, когда они, наконец, будут инициализированыЯ признаю, что рассуждать об этом немного бессмысленно, так как мы будем вне определенного поведения.

1 голос
/ 18 августа 2010

Единственный раз, когда вы можете сделать это, это когда что-то получено из шаблона, который сам параметризован:

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()
  {
  }
};

Обратите внимание, что doSomething является общедоступным, а не виртуальным.

Мы можем сделать static_cast с производным, потому что известно, что производный является производным типом.

Получение чего-либо из базы, параметризованной само по себе, - странная вещь, которую нужно делать в лучшие времена.Говорят, что когда команда ATL в Microsoft использовала его, они спрашивали команду компилятора C ++, была ли она действительной, и никто не был уверен, хотя она действительна, потому что построение шаблона зависит от имен следующим образом:

Сначала шаблон доступен, но не используется в классе.Затем имя derived доступно.Затем он создает макет base<derived> - это требует знания переменных-членов и виртуальных функций, если только это не зависит от знания макета derived (с указателями и ссылками все в порядке), все будет хорошо.Затем он создаст макет derived и, наконец, создаст функции-члены derived, которые могут включать создание функций-членов для base<derived>.Таким образом, до тех пор, пока base<derived> не содержит производную переменную-член (базовые классы никогда не могут содержать переменную-член типа, производного от себя) или виртуальную функцию, требующую знания макета производного, мы действительно можем выполнить сложный образо наследовании выше.

Это включает в себя возможность вызывать не виртуальные открытые члены derived из base во время построения, потому что это уже часть базы.Есть серьезные ограничения на это.В частности, если doSomething() зависит от чего-либо созданного в конструкторе derived, оно не будет работать, так как derived еще не было построено.

Теперь, действительно ли это хорошая идея?Нет.

1 голос
/ 18 августа 2010

Нет, извините. :( Может компилироваться в один или два компилятора C ++, но это не рекомендуется. Из раздела C ++ FAQ Lite 10.7 :

[10.7] Если вы используете указатель this в конструкторе?

[... чик ...]

Вот то, что никогда не работает: {тело} конструктора (или функция вызывается из конструктора) не может перейти к производному классу вызывая виртуальную функцию-член, которая переопределяется в производном классе. Если Ваша цель состояла в том, чтобы добраться до переопределенного функция в производном классе, вы не получит то, что вы хотите. Обратите внимание, что вы не получится переопределить в производный класс независимо от того, как вы вызовите функцию виртуального члена: явно используя этот указатель (например, this-> method ()), неявно используя указатель this (например, method ()), или даже вызов какого-то другого функция, которая вызывает виртуальный член Функция на вашем этом объекте. Суть заключается в следующем: , даже если вызывающая сторона строит объект производный класс, во время конструктора базового класса, ваш объект не еще этого производного класса. У вас есть был предупрежден.

ПРИМЕЧАНИЕ: выделение мое.

Подробнее по ссылке

0 голосов
/ 18 августа 2010

Простое проектное решение заключается в использовании агрегации вместо наследования .

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...