Russian Qt Forum

Программирование => С/C++ => Тема начата: trot от Апрель 04, 2012, 14:01



Название: Вызов метода дочернего класса
Отправлено: trot от Апрель 04, 2012, 14:01
Есть родительский класс и пронаследованный от него дочерний.
Существует ли возможность вызова метода дочернего класса из родительского. Если - да, то как?

Спасибо.


Название: Re: Вызов метода дочернего класса
Отправлено: mutineer от Апрель 04, 2012, 14:03
виртуальные методы


Название: Re: Вызов метода дочернего класса
Отправлено: trot от Апрель 04, 2012, 14:41
Вот пример, который работает не так как хочется. Что я делаю неправильно?
Код
C
class I{
public:
virtual void create()=0;
}
 
class A:public I {
public:
A(){
create();
};
~A();
virtual void create(){};
 
};
 
class B:public B{
public:
B();
~B();
virtual void create(){int i = 1+1;};
};
 
int main(int argc, char *argv[]){
B * b = new B();
}

надо чтобы сработал метод create() класса B, а не А,
можно конечно написать так
Код
C
int main(int argc, char *argv[]){
B * b = new B();
          b->create();
}
Но хотелось бы всю типовую логику записать в базовый класс, а реализацию логического действия в производном классе.




Название: Re: Вызов метода дочернего класса
Отправлено: mutineer от Апрель 04, 2012, 14:48
Неправильно вызывать виртуальный метод в конструкторе базового класса


Название: Re: Вызов метода дочернего класса
Отправлено: Igors от Апрель 04, 2012, 15:09
Когда выполняется конструктор базового класса (A) все виртуалы работают как для A, и sizeof(*this) вернет sizeof(A). Порожденный класс (B) в этот момент еще как бы "не создан"


Название: Re: Вызов метода дочернего класса
Отправлено: Пантер от Апрель 04, 2012, 15:10
И с деструктором такая же беда.


Название: Re: Вызов метода дочернего класса
Отправлено: m_ax от Апрель 04, 2012, 15:19
Это классический пример на шаблонах:

Код
C++ (Qt)
#include <iostream>
 
template<class Derived>
class A {
  public:
     A(Derived* d){d->init();}
};
 
class B : public A<B> {
  public:
     B():A<B>(this){}
 
     void init(){std::cout << "B" << std::endl;}  
};
class C : public A<C> {
  public:
     C():A<C>(this){}
 
     void init(){std::cout << "C" << std::endl;}  
};
 
int main()
{
  B b;
  C c;
  return 0;
}
 


Название: Re: Вызов метода дочернего класса
Отправлено: Akon от Апрель 05, 2012, 08:01
Этот подход имеет ограниченное применение, хотя такие вещи составляют уникальную мощь C++! В ООП на C++ использование этого подхода чревато трудноуловимыми багами:
Код:
#include <iostream>
#include <string>

class String
{
public:
String() : marker_(0x047F4578) {}
std::string data() const { return 0x047F4578 == marker_ ? "Constructed" : "Not constructed"; }

private:
int marker_;
};

template<class Derived>
class A
{
public:
A(Derived* d){d->init();}
};

class B : public A<B>
{
public:
B():A<B>(this){}

void init(){std::cout << "B: String member " << string_.data() << std::endl;}

private:
String string_;
};

int main()
{
B b;
return 0;
}

Т.е. мы имеем в B::init() несконструированный член B::string_! Собственно, по этой причине в С++ и не вызываются из конструкторов и деструкторов виртуальные методы, поскольку всегда есть возможность использования неинициализированных членов. В языках, где нет объектов-значений такой проблемы принципиально нет, поскольку базовый класс имеет возможность инициализировать всю память (нулями).


Название: Re: Вызов метода дочернего класса
Отправлено: mutineer от Апрель 05, 2012, 10:14
Собственно, по этой причине в С++ и не вызываются из конструкторов и деструкторов виртуальные методы, поскольку всегда есть возможность использования неинициализированных членов.

Они не вызываются скорее потому, что таблица виртуальных функций для дочерних классов на этапе конструктора родителя еще не построена


Название: Re: Вызов метода дочернего класса
Отправлено: Akon от Апрель 05, 2012, 11:04
Ну хорошо, а что мешает эту таблицу построить (таблицы виртуальных функций строятся на этапе компиляции)? То, что в конструкторе vmt pointer всегда указывает на vmt данного типа, а не дочернего, как в некоторых других языках, - это как раз самый простой способ реализации предотвращения полиморфного поведения (виртуального вызова).


Название: Re: Вызов метода дочернего класса
Отправлено: Igors от Апрель 05, 2012, 11:07
Т.е. мы имеем в B::init() несконструированный член B::string_! Собственно, по этой причине в С++ и не вызываются из конструкторов и деструкторов виртуальные методы, поскольку всегда есть возможность использования неинициализированных членов.
Да, все четко. Спасибо за разъяснение этого нюанса


Название: Re: Вызов метода дочернего класса
Отправлено: demaker от Апрель 16, 2012, 13:49
Что я ничего не понял ???

Понял одно, что в конструкторе класса унаследованного от абстрактного нельзя вызывать виртуальные методы.


Название: Re: Вызов метода дочернего класса
Отправлено: RealDuke от Апрель 16, 2012, 14:11
Понял одно, что в конструкторе класса унаследованного от абстрактного нельзя вызывать виртуальные методы.
Как минимум странный  и неверный вывод, рушащий весь принцип ООП :) На этапе конструктора производного класса таблица виртуальных функций уже сформирована. Только вот зачем виртуальные функции вызывать в конструкторе (следовательно в объекте известного типа) для меня вопрос.