Russian Qt Forum
Ноябрь 23, 2024, 08:06 *
Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.
Вам не пришло письмо с кодом активации?

Войти
 
  Начало   Форум  WIKI (Вики)FAQ Помощь Поиск Войти Регистрация  

Страниц: 1 [2]   Вниз
  Печать  
Автор Тема: Использование чистой виртуальной функции в конструкторе  (Прочитано 13330 раз)
Old
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 4350



Просмотр профиля
« Ответ #15 : Май 18, 2013, 15:06 »

Правда никакой он не void (не адрес) а, полагаю, индекс/ID (хорошо видно напр в 64). Хотя это не документировано - никогда не видел др реализации ни в одном компиляторе
Не знаю куда вы смотрите, но это именно адрес таблицы, в которой лежат адреса функций (в x86_64 в том числе).

Код
C++ (Qt)
       void **vtbl = reinterpret_cast<void***>( this )[ 0 ];
       while( *vtbl )
               std::cout << *vtbl++ << std::endl;
 
Записан
CuteBunny
Гость
« Ответ #16 : Май 22, 2013, 14:43 »

Добрый день.
Пытаюсь разобраться со следующим кодом:
Код:
#include <iostream>

using namespace std;

class AbstractClass
{
protected:
  virtual void AbstractFunc() = 0;
public:
  AbstractClass();
};

AbstractClass::AbstractClass()
{
  AbstractFunc();
}

int main()
{
  return 0;
}
На этот код при компиляции мне выдается сразу куча сообщений:
Код:
In constructor 'AbstractClass::AbstractClass()':
warning: abstract virtual 'virtual void AbstractClass::AbstractFunc()' called from constructor
undefined reference to `AbstractClass::AbstractFunc()'
undefined reference to `AbstractClass::AbstractFunc()'
collect2: ld returned 1 exit status
Причем, если сделать AbstractFunc() просто виртуальной - все становится просто замечательно.
Помогите разобраться, пожалуйста

Добавлю свои 5коп.
В принципе вы можете определить чисто виртуальную функцию, тогда в этом примере компилятор ошибку не выдаст, но предупреждение все равно будет кидать.

Код
C++ (Qt)
#include <iostream>
 
using namespace std;
 
class AbstractClass
{
protected:
 virtual void AbstractFunc() = 0;
public:
 AbstractClass();
};
 
void AbstractClass::AbstractFunc() {}
 
AbstractClass::AbstractClass()
{
 AbstractFunc();
}
 
int main()
{
 return 0;
}
 

Хммм, интересно, если чисто виртуальную функцию можно определить, то в теории её можно вызвать?...
Записан
lcs-perm
Гость
« Ответ #17 : Май 24, 2013, 21:28 »

После непродолжительных раздумий решил для себя обозначенную в теме проблему следующим образом
Код:
#include <iostream>

using namespace std;

class AbstractClass
{
public:
  virtual void AbstractFunc() = 0;
};
template <class TChild> AbstractClass* AbstractClass_Create(AbstractClass *instance)
{
  TChild* result = (TChild*)instance;
  result->AbstractFunc();
  return result;
}
AbstractClass* AbstractClass_Create(AbstractClass *instance);

class RealClass01: public AbstractClass
{
friend AbstractClass* AbstractClass_Create<RealClass01>(AbstractClass *instance);
protected:
  void AbstractFunc() { cout << "RealClass01" << endl; }
  virtual void RealFunc() = 0;
};
template <class TChild> RealClass01* RealClass01_Create(RealClass01 *instance)
{
  TChild* result = (TChild*)AbstractClass_Create<RealClass01>(instance);
  result->RealFunc();
  return result;
}
RealClass01* RealClass01_Create(RealClass01 *instance);

class FactClass01: public RealClass01
{
friend RealClass01* RealClass01_Create<FactClass01>(RealClass01 *instance);
protected:
  void RealFunc() { cout << "FactClass01" << endl; }
};

class RealClass02: public AbstractClass
{
friend AbstractClass* AbstractClass_Create<RealClass02>(AbstractClass *instance);
protected:
  void AbstractFunc() { cout << "RealClass02" << endl; }
};

int main()
{
  AbstractClass *fc_01 = RealClass01_Create<FactClass01>(new FactClass01);
  AbstractClass *rc_02 = AbstractClass_Create<RealClass02>(new RealClass02);
  delete fc_01;
  delete rc_02;
  return 0;
}
В результате запуска этого приложения получаю такой вывод:
Код:
RealClass01
FactClass01
RealClass02
Есть, конечно, некоторая громоздкость, но на вскидку особых недостатков в этом решении я не заметил.
Хотелось бы обсудить, чтобы во-первых - эти самые недостатки увидеть; и, во-вторых - может найдется более приятное для глаза решение
Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #18 : Май 25, 2013, 09:53 »

После непродолжительных раздумий решил для себя обозначенную в теме проблему ..
..может найдется более приятное для глаза решение
Если поубирать ненужные template и поработать с именами - для глаза будет приятнее. В Вашем решении ничего нового не видно (что не значит "плохо"). После того как все конструкторы отработали - любые виртуалы выполняются "как доктор прописал".
Записан
lcs-perm
Гость
« Ответ #19 : Май 27, 2013, 20:49 »

Если поубирать ненужные template и поработать с именами - для глаза будет приятнее. В Вашем решении ничего нового не видно (что не значит "плохо"). После того как все конструкторы отработали - любые виртуалы выполняются "как доктор прописал".
Ну на оригинальность я и не претендую особо. А вот насчет ненужных template'ов хотелось бы поподробнее.
Мне кажется, они обеспечивают возможность не переписывать дружественный конструктор отдельно для каждого класса-наследника. Т.е. именно так, как хочется - один абстрактный конструктор на всех наследников.
Или я чего то не понимаю?
Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #20 : Май 28, 2013, 09:57 »

А вот насчет ненужных template'ов хотелось бы поподробнее.
Мне кажется, они обеспечивают возможность не переписывать дружественный конструктор отдельно для каждого класса-наследника. Т.е. именно так, как хочется - один абстрактный конструктор на всех наследников.
Этого не видно
Код:
  AbstractClass *fc_01 = RealClass01_Create<FactClass01>(new FactClass01);
  AbstractClass *rc_02 = AbstractClass_Create<RealClass02>(new RealClass02);
Зачем нужно несколько template и оберток если никакой общности все равно не достигается? Т.е. один класс создаете одним template, другой другим. Не проще ли было "в стиле начинающего"
Код
C++ (Qt)
 AbstractClass *fc_01 = new FactClass01;
 fc_01->AbstractFunc();
 AbstractClass *rc_02 = new RealClass02;
 fc_02->AbstractFunc();
 
Что хотя и примитивно, но куда яснее и короче. Если же метод "неотъемлемая часть" конструктора, то сделать его невиртуальным, при этом виртуальный может просто его вызвать
Записан
lcs-perm
Гость
« Ответ #21 : Май 28, 2013, 16:55 »

Ну, в классе RealClass01 я использовал абстрактный метод, чтобы проверить абстрактное наследование с глубиной больше чем 1.
А если бы в RealClass01 не было абстрактного метода, то код мог бы быть таким
Код:
AbstractClass *rc_01 = AbstractClass_Create<RealClass01>(new RealClass01);
AbstractClass *rc_02 = AbstractClass_Create<RealClass02>(new RealClass02);
И был бы только один раз написанный конструктор-обертка, который бы в дальнейшем объявлялся всем наследникам как дружественный.
Конечно, когда конструктор состоит из одного оператора, выгода не очевидна. А вот для достаточно сложных случаев все будет выглядеть совсем по другому.

Ну ладно. Спасибо Вам за потраченное время. По крайней мере, у меня была возможность сравнить все плюсы и минусы нескольких подходов.
Записан
ctin
Гость
« Ответ #22 : Июнь 07, 2013, 13:00 »

Добавлю от себя. Сталкивался с подобной проблемой, когда была куча диалоговых окон с различным функционалом, который задавался при инициализации.
Решил так:

Код:
{
    AbstractDialog  *pDialog = createDialog("testName");
    if(pDialog->initFunc()) //это виртуальный метод.
        pDialog->exec(); //в конструкторе флаг DeleteOnClose
    else
        delete pDialog;
}
Записан
Страниц: 1 [2]   Вверх
  Печать  
 
Перейти в:  


Страница сгенерирована за 0.172 секунд. Запросов: 22.