Модераторы: Daevaorn

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> механизм виртуальных функций (не работает:(), иллюстрация классическим СИ 
V
    Опции темы
Podarochek
Дата 23.5.2008, 16:02 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 94
Регистрация: 2.11.2007

Репутация: нет
Всего: нет



ссори, может я не так выразился...конечно же реализация будет предполагать С++, но имеется в виду раскрыть карты С++ и показать механизм явно (таблицу указателей). как сказал xvr  этот механизм и так есть уже в С++

Добавлено через 13 минут и 5 секунд
Я думаю по теме (еще одна ошибка) хоть убей, не могу понять что от меня хотят, кажись все реализованно как говорят по учебнику, а пишет:

Error    3    error C2259: 'Boss' : cannot instantiate abstract class    
Error    4    error C2259: 'CommissionWorker' : cannot instantiate abstract class    

и все...:(

Добавлено через 14 минут и 32 секунды
Код

#include <iostream> 
#include <cstring>
#include <cassert>
#include <iomanip>
using namespace std;; 


class Employee { 
public: 
    Employee( const char *, const char * ); 
     ~Employee () ; 
    const char *getFirstName() const; 
    const char *getLastName() const; 
 
//виртуальная функция образует абстрактный базовый класс Employee
    virtual double earning() const=0;//чистая виртуальная функция
    virtual void print() const;//виртуальная
private:
    char *firstName;
    char *lastName;
};

//Конструктор динамически выделяет память для
//имени и фамилии и использует strcpy для копирования
//имени и фамилии в объект
Employee::Employee( const char *first, const char *last )
{
    firstName = new char[ strlen( first) + 1 ]; 
    assert( firstName != 0 );//проверка выделения памяти
    strcpy( firstName, first); 
    lastName = new char[ strlen( last) + 1 ]; 
    assert( lastName != 0 ); // проверка выделения памяти
    strcpy( lastName, last); 
}

//деструктор освобождает динамически выделенную память
Employee::~Employee()
{
    delete [] firstName;//освобождение памяти
    delete [] lastName;//освобождение памяти
}

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

const char *Employee::getFirstName() const 

return firstName; //вызывающая программа должна осовободить память


//печать имени рабочего из класса Employee
void Employee::print() const 

    cout << firstName << " "<< lastName;
}

//класс Boss, производный от класса Employee 
class Boss :    public Employee
{
public: 
    Boss( const char *, const char *, double =0.0);
    void setWeeklySalary( double); 
    virtual double earnings() const; 
    virtual void print() const; 
private: 
    double weeklySalary; 
};

//определения функций-членов класса Boss

//конструктор класса Boss

Boss::Boss( const char *first, const char *last, double s ) 
        : Employee( first, last) //вызов конструктора базового класса
{
    setWeeklySalary ( s ); 


//установка еженедельного оклада для класса Boss
void Boss::setWeeklySalary( double s )
{
    weeklySalary = s > 0? s : 0; 

 
//начисление заработной платы в классе Boss
double Boss::earnings() const { return weeklySalary;} 

//печать имени служащего из класса Boss
void Boss::print() const 
{     
    cout << "\n    Administrator: "; 
    Employee::print (); 
}

//класс CommissionWorker, производный от класса Employee
class CommissionWorker : public Employee {
public: 
    CommissionWorker( const char *, const char *,double = 0.0, double = 0.0,int = 0 ); 
    void setSalary( double); 
    void setCommission( double); 
    void setQuantity( int); 
    virtual double earnings() const; 
    virtual void print() const; 
private: 
    double salary;//базовая заработная плата за неделю
    double commission;//комисионные от продажи одного изделия
    int quantity; //количество проданных изделий за неделю
}; 
//определение функций-членов класса CommissionWorker

//конструктор класса CommissionWorker
CommissionWorker::CommissionWorker(const char *first, const char *last, double s, double c, int q )
            : Employee( first, last) //конструктлор базового класса 
{
    setSalary( s );
    setCommission( c );
    setQuantity( q );
}

// установка еженедельного оклада для класса CommissionWorker 
void CommissionWorker::setSalary( double s) 
{
    salary = s > 0 ? s : 0; }

//установка комисионных для класса CommissionWorker 
void CommissionWorker::setCommission( double c ) 
{ commission = c > 0 ? c : 0; } 

//установка количества продаж изделий для класса CommissionWorker 
void CommissionWorker::setQuantity( int q ) 
{quantity =q > 0 ? q : 0; } 

//определение зароботной платы служащих из класса CommissionWorker 
double CommissionWorker::earnings() const 

    return  salary + commission * quantity; 


//Печать имени служащего из класса CommissionWorker 
void CommissionWorker::print() const    
{
    cout << "\nSlugaschij na komisionnux: ";
    Employee::print(); 
}

//создать вызов виртуальной функции ссылкой базового класса,
//используя динамическое связывание
void virtualViaPointer(const Employee* baseClassPtr)
{
    baseClassPtr->print();
    cout<<"zarabotal $"<<baseClassPtr->earning();
}

//создать вызов виртуальной функции ссылкой базового класса,
//используя динамическое связывание
void virtualViaReference(const Employee& baseClassRef)
{
    baseClassRef.print();
    cout<<"zarabotal $"<<baseClassRef.earning();
}
void main()
{
    Boss b("John","Smith", 800.00);
    b.print();//статическое связывание
    cout<<"zarabotal $"<<b.earnings();//статическое связывание

    virtualViaPointer(&b);//использует динамическое связывание
    virtualViaReference(b);//использует динамическое связывание

    CommissionWorker c("Sue", "Jones", 200.0, 3.0, 150);
    c.print();//статическое связывание
    cout<<"zarabotal $"<<c.earnings();//статическое связывание

    virtualViaPointer(&c);//использует динамическое связывание
    virtualViaReference(c);//использует динамическое связывание


}


PM MAIL   Вверх
mes
Дата 23.5.2008, 16:18 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


любитель
****


Профиль
Группа: Участник Клуба
Сообщений: 7954
Регистрация: 14.1.2006

Репутация: 144
Всего: 250



Цитата(Podarochek @  23.5.2008,  16:02 Найти цитируемый пост)
имеется в виду раскрыть карты С++ и показать механизм явно (таблицу указателей). как сказал xvr  этот механизм и так есть уже в С++ 


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

кстати насчет vtable - на самом деле таблица не представлена в виде набора  массива однотипных указетелей 
а виде набора разных структур, содержаших  разнотипные указатели

вот доработал еше чтоб больше походило на реальный механизм - хотя и еше есть что доработать:
Код

#include <cstdlib>
#include <iostream>

using namespace std;


class A
{
   protected:
// vtable-type -----------------------------------------------------------------
    struct A_vtable_t
    {
            A_vtable_t() {};

            void (*f1)(void* __this);
            void (*f2)(void* __this, int i);
            void (*f3)(void* __this, int i);
    };
//------------------------------------------------------------------------------

  public:
    A() { A_vtable_set(A_vtable_get_for_A()); }

  public:
// pseudo-virtual-interface
    void f1()              { A_vtable_get()->f1(this); }
    void f2(int i)         { A_vtable_get()->f2(this, i); }
    void f3(int i)         { A_vtable_get()->f3(this, i); }

  private:
    void priv_fn() { cout << "  A::private_function()" ; }

  private:
// pseudo-virtual-implementation
               void   vf1()       { cout << "A::f1() {";   priv_fn();  cout <<"; };"<< endl;  };
               void   vf2(int i)  { cout << "A::f2(int);" << endl; };
               void   vf3(int i)  { cout << "A::f3(int);" << endl; };


//vtable-details ---------------------------------------------------------------

// call_helper
  private:
        static void __vf1(void* __this)         { (reinterpret_cast<A*>(__this))->vf1();  };
        static void __vf2(void* __this, int i)  { (reinterpret_cast<A*>(__this))->vf2(i); };
        static void __vf3(void* __this, int i)  { (reinterpret_cast<A*>(__this))->vf3(i); };

  public:
//vtable-initialization
        static void A_vtable_init () {
                                       A_vtable_get_for_A()->f1=&A::__vf1;
                                       A_vtable_get_for_A()->f2=&A::__vf2;
                                       A_vtable_get_for_A()->f3=&A::__vf3;
                                     };

   protected:

        static A_vtable_t *A_vtable_get_for_A()       { static A_vtable_t  A_vtable_for_A; return &A_vtable_for_A; }

        A_vtable_t *A_vtable_get()                    { return A_vtable_ptr; }
        A_vtable_t *A_vtable_set(A_vtable_t * vtable) { A_vtable_ptr = vtable; }

   private:
        A_vtable_t * A_vtable_ptr;
//------------------------------------------------------------------------------

};

class B : public A
{
 public:
        B() { A_vtable_set(A_vtable_get_for_B()); }

 private:
        void priv_fn() { cout << "  B::private_function()" ; }

 private:
// pseudo-virtual-implementation
        void   vf1()       { cout << "B::f1() {"; priv_fn(); cout <<"; };"<< endl; };
        void   vf2(int i)  { cout << "B::f2(int);" << endl; };


//vtable-details ---------------------------------------------------------------
 private:
        static void __vf1(void* __this)         { (reinterpret_cast<B*>(__this))->vf1();  };
        static void __vf2(void* __this, int i)  { (reinterpret_cast<B*>(__this))->vf2(i); };

        static A_vtable_t *A_vtable_get_for_B() { static A_vtable_t  A_vtable_for_B; return &A_vtable_for_B; }

  public:
//vtable-initialization
        static void A_vtable_init () {
                                       *A_vtable_get_for_B()=*A_vtable_get_for_A();
                                        A_vtable_get_for_B()->f1=&B::__vf1;
                                        A_vtable_get_for_B()->f2=&B::__vf2;
                                     };
//------------------------------------------------------------------------------
};


int main(int argc, char *argv[])
{
    A::A_vtable_init ();
    B::A_vtable_init ();

    A a;
    a.f1();
    a.f2(2);
    a.f3(6);

    cout <<endl;

    B b;
    b.f1();
    b.f2(3);
    b.f3(4);
    cout <<endl;

    A *pa=&b;
    pa->f1();
    pa->f2(4);
    pa->f3(5);
    cout <<endl;

    system("PAUSE");
    return EXIT_SUCCESS;
}




Это сообщение отредактировал(а) mes - 23.5.2008, 16:29


--------------------
PM MAIL WWW   Вверх
Podarochek
Дата 23.5.2008, 16:33 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 94
Регистрация: 2.11.2007

Репутация: нет
Всего: нет



спасибо mes буду разбираться
по поводу второго примера подскажешь?
PM MAIL   Вверх
mes
Дата 23.5.2008, 16:41 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


любитель
****


Профиль
Группа: Участник Клуба
Сообщений: 7954
Регистрация: 14.1.2006

Репутация: 144
Всего: 250



Цитата(Podarochek @  23.5.2008,  16:02 Найти цитируемый пост)
Error    3    error C2259: 'Boss' : cannot instantiate abstract class    
Error    4    error C2259: 'CommissionWorker' : cannot instantiate abstract class    


у тебя в этих классах есть абстрактные функции, а такие обжекты создавать нельзя

Код

class A
{
 public:
 virtual void abstract_fn() =0; //  абстрактная
};

class A1:public A
{
  public:
   virtual void abstract_fn() { .. } // реализация  - обьект такого типа создавть можно
};

// А * pa = new A; // нельзя 
А * pa = new A1; // создается А1, а интерфейс использоется от А


Добавлено через 1 минуту и 22 секунды
глянул в код - так у тебя у самого черным по белому написано
Код

    virtual double earning() const=0;//чистая виртуальная функция

 smile 


--------------------
PM MAIL WWW   Вверх
Podarochek
Дата 23.5.2008, 17:07 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 94
Регистрация: 2.11.2007

Репутация: нет
Всего: нет



ну да базовый класс создан абстрактным, а производный класс например я изменил ->(теперь без virtual)
//класс CommissionWorker, производный от класса Employee
class CommissionWorker : public Employee {
public: 
    CommissionWorker( const char *, const char *,double = 0.0, double = 0.0,int = 0 ); 
    void setSalary( double); 
    void setCommission( double); 
    void setQuantity( int); 
    double earnings() const; 
    void print() const; 
private: 
    double salary;//базовая заработная плата за неделю
    double commission;//комисионные от продажи одного изделия
    int quantity; //количество проданных изделий за неделю
}; 

всеравно ошибки. Объекты производных классов разве нельзя создавать?

Добавлено через 4 минуты и 27 секунд
Цитата(mes @  23.5.2008,  16:41 Найти цитируемый пост)
class A
{
 public:
 virtual void abstract_fn() =0; //  абстрактная
};

class A1:public A
{
  public:
   virtual void abstract_fn() { .. } // реализация  - обьект такого типа создавть можно
};

// А * pa = new A; // нельзя 
А * pa = new A1; // создается А1, а интерфейс использоется от А

 
например объект А1 ob;
PM MAIL   Вверх
mes
Дата 23.5.2008, 17:33 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


любитель
****


Профиль
Группа: Участник Клуба
Сообщений: 7954
Регистрация: 14.1.2006

Репутация: 144
Всего: 250



Цитата(Podarochek @  23.5.2008,  17:07 Найти цитируемый пост)
например объект А1 ob; 

можно создавть объект и в стеке и по new при условие что у класса нет абстрактных методов..
пояснение: если у предка есть абстрактные методы - то они все должны получить реализацию у потомка

Цитата(Podarochek @  23.5.2008,  17:07 Найти цитируемый пост)
производный класс например я изменил ->(теперь без virtual)

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

Добавлено через 1 минуту и 8 секунд
P.S зря ты обе темы в одной ветке запостил .. путает 


--------------------
PM MAIL WWW   Вверх
Podarochek
Дата 23.5.2008, 17:50 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 94
Регистрация: 2.11.2007

Репутация: нет
Всего: нет



smile 

earnings вместо earning!!! Я балбес. Конечно они должны быть одинаковы...откуда взяласт s до сих пор не могу понять smile

Добавлено через 2 минуты и 3 секунды
о втором посте(т.е. ответвлении от основной темы) забыли...прошу прощения!!! smile 
PM MAIL   Вверх
mes
Дата 24.5.2008, 15:42 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


любитель
****


Профиль
Группа: Участник Клуба
Сообщений: 7954
Регистрация: 14.1.2006

Репутация: 144
Всего: 250



Вот еше раз доработал код, 
на этот наконец то отделил технические операции от представления класса : 
этот вариант можно считать законченым  (потому как для дальнейших улучшений требуются шаблоны, а это будет вне задания ) 
 smile 

Код

#include <cstdlib>
#include <iostream>

using namespace std;


namespace A_vtable
{
// vtable-type -----------------------------------------------------------------
    struct type
    {
            void (*f1)(void* __this);
            void (*f2)(void* __this, int i);
            void (*f3)(void* __this, int i);
    };
    static A_vtable::type *get_for_A() { static type  vtable; return &vtable; }
    static A_vtable::type *get_for_B() { static type  vtable; return &vtable; }
//------------------------------------------------------------------------------
};

class A
{
    friend class __A;
  public:
    A() { A_vtable_set(A_vtable::get_for_A()); }

  private:
    void priv_fn() { cout << "  A::private_function()" ; }

  private:
// pseudo-virtual-implementation
               void   vf1()       { cout << "A::f1() {";   priv_fn();  cout <<"; };"<< endl;  };
               void   vf2(int i)  { cout << "A::f2(int);" << endl; };
               void   vf3(int i)  { cout << "A::f3(int);" << endl; };

  public:
// pseudo-virtual-interface ----------------------------------------------------
    void f1()              { A_vtable_get()->f1(this); }
    void f2(int i)         { A_vtable_get()->f2(this, i); }
    void f3(int i)         { A_vtable_get()->f3(this, i); }

   public:
        A_vtable::type *A_vtable_get()                        { return A_vtable_ptr; }
        A_vtable::type *A_vtable_set(A_vtable::type * vtable) { A_vtable_ptr = vtable; }

   private:
        A_vtable::type * A_vtable_ptr;
//------------------------------------------------------------------------------
};

class B : public A
{
        friend class __B;
 public:
        B() {  A_vtable_set(A_vtable::get_for_B());  }

 private:
        void priv_fn() { cout << "  B::private_function()" ; }

 private:
// pseudo-virtual-implementation
        void   vf1()       { cout << "B::f1() {"; priv_fn(); cout <<"; };"<< endl; };
        void   vf2(int i)  { cout << "B::f2(int);" << endl; };
};

// Helpers ----------------------------------------------------------------------
// обслуживание виртуального механизма:
class __A
{
  private:
        static void __vf1(void* __this)         { (reinterpret_cast<A*>(__this))->vf1();  };
        static void __vf2(void* __this, int i)  { (reinterpret_cast<A*>(__this))->vf2(i); };
        static void __vf3(void* __this, int i)  { (reinterpret_cast<A*>(__this))->vf3(i); };

  public:
        static void __init () {
                                 A_vtable::get_for_A()->f1=&__A::__vf1;
                                 A_vtable::get_for_A()->f2=&__A::__vf2;
                                 A_vtable::get_for_A()->f3=&__A::__vf3;
                              };
};

class __B
{
  private:
        static void __vf1(void* __this)         { (reinterpret_cast<B*>(__this))->vf1();  };
        static void __vf2(void* __this, int i)  { (reinterpret_cast<B*>(__this))->vf2(i); };

  public:
        static void __init () {
                                       *A_vtable::get_for_B()=*A_vtable::get_for_A();
                                        A_vtable::get_for_B()->f1=&__B::__vf1;
                                        A_vtable::get_for_B()->f2=&__B::__vf2;
                              };
};
//------------------------------------------------------------------------------

int main(int argc, char *argv[])
{

    __A::__init ();
    __B::__init ();

    A a;
    a.f1();
    a.f2(2);
    a.f3(6);

    cout <<endl;

    B b;
    b.f1();
    b.f2(3);
    b.f3(4);
    cout <<endl;

    A *pa= new B();
    pa->f1();
    pa->f2(4);
    pa->f3(5);

    delete pa;

    cout <<endl;

    system("PAUSE");
    return EXIT_SUCCESS;
}




--------------------
PM MAIL WWW   Вверх
mes
Дата 24.5.2008, 18:12 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


любитель
****


Профиль
Группа: Участник Клуба
Сообщений: 7954
Регистрация: 14.1.2006

Репутация: 144
Всего: 250



Цитата(mes @  24.5.2008,  15:42 Найти цитируемый пост)
этот вариант можно считать законченым 

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

Код

#include <cstdlib>
#include <iostream>

using namespace std;


class A;
class B;

namespace A_vtable
{
// vtable-type -----------------------------------------------------------------
//
    struct type
    {
            void (*f1)(void* __this);
            void (*f2)(void* __this, int i);
            void (*f3)(void* __this, int i);

    };
    static A_vtable::type *get(A*) { static type vtable; return &vtable; }
    static A_vtable::type *get(B*) { static type vtable; return &vtable; }

    class ptr
    {
      public:
        type * get()                     { return p_vtable;   }
        void set (type * vtable)         { p_vtable = vtable; }
        operator type*()                 { return get();      }
        void operator () (type * vtable) { set(vtable);       }
      private:
        A_vtable::type * p_vtable;
     };
//------------------------------------------------------------------------------
};

class A
{
    friend class __A;
  public:
    A() { A_vtable_ptr(A_vtable::get(this)); }

  private:
    void priv_fn() { cout << "  A::private_function()" ; }

  private:
// pseudo-virtual-implementation
// отсутствует в абстракном классе
               void   vf1()       { cout << "A::f1() {";   priv_fn();  cout <<"; };"<< endl;  };
               void   vf2(int i)  { cout << "A::f2(int);" << endl; };
               void   vf3(int i)  { cout << "A::f3(int);" << endl; };

  public:
// pseudo-virtual-interface ----------------------------------------------------
    void f1()              { (*A_vtable_ptr).f1(this); }
    void f2(int i)         { (*A_vtable_ptr).f2(this, i); }
    void f3(int i)         { (*A_vtable_ptr).f3(this, i); }

   protected:
        A_vtable::ptr A_vtable_ptr;
//------------------------------------------------------------------------------
};

class B : public A
{
        friend class __B;
 public:
        B() {  A_vtable_ptr(A_vtable::get(this));  }

 private:
        void priv_fn() { cout << "  B::private_function()" ; }

 private:
// pseudo-virtual-implementation
        void   vf1()       { cout << "B::f1() {"; priv_fn(); cout <<"; };"<< endl; };
        void   vf2(int i)  { cout << "B::f2(int);" << endl; };
};

// Helpers ----------------------------------------------------------------------
// обслуживание виртуального механизма:
class __A
{
  protected:
        static void __vf1(void* __this)         { (reinterpret_cast<A*>(__this))->vf1();  };
        static void __vf2(void* __this, int i)  { (reinterpret_cast<A*>(__this))->vf2(i); };
        static void __vf3(void* __this, int i)  { (reinterpret_cast<A*>(__this))->vf3(i); };

  public:
        static void __init () {
                                 A_vtable::get((A*)NULL)->f1=&__A::__vf1;
                                 A_vtable::get((A*)NULL)->f2=&__A::__vf2;
                                 A_vtable::get((A*)NULL)->f3=&__A::__vf3;
                              };
};

class __B: protected __A
{
  private:
        static void __vf1(void* __this)         { (reinterpret_cast<B*>(__this))->vf1();  };
        static void __vf2(void* __this, int i)  { (reinterpret_cast<B*>(__this))->vf2(i); };

  public:
        static void __init () {
                                        A_vtable::get((B*)NULL)->f1=&__B::__vf1;
                                        A_vtable::get((B*)NULL)->f2=&__B::__vf2;
                                        A_vtable::get((B*)NULL)->f3=&__B::__vf3;
                              };
};
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------

int main(int argc, char *argv[])
{
    __A::__init ();
    __B::__init ();

    A a;
    a.f1();
    a.f2(2);
    a.f3(6);

    cout <<endl;

    B b;
    b.f1();
    b.f2(3);
    b.f3(4);
    cout <<endl;

    A *pa= new B();
    pa->f1();
    pa->f2(4);
    pa->f3(5);

    delete pa;

    cout <<endl;

    system("PAUSE");
    return EXIT_SUCCESS;
}



Это сообщение отредактировал(а) mes - 24.5.2008, 19:04


--------------------
PM MAIL WWW   Вверх
mes
Дата 24.5.2008, 20:21 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


любитель
****


Профиль
Группа: Участник Клуба
Сообщений: 7954
Регистрация: 14.1.2006

Репутация: 144
Всего: 250



Podarochek, не думал, что меня так зацепит эта тема ))
вот еше немного добавил в илюстрацию 
теперь есть:
псевдо pure-абстрактный класс,
и два класса: один с частичной другой с полной перегрузкой абстрактных методов
Код

#include <cstdlib>
#include <iostream>

using namespace std;


class A;
class B;
class C;

namespace A_vtable
{
// vtable-type -----------------------------------------------------------------
//
    struct type
    {
        void (*f1)(void* __this);
        void (*f2)(void* __this, int i);
        void (*f3)(void* __this, int i);
    };

// ниже нужен шаблон вместо повторения
    static A_vtable::type *get(A*) { static type vtable; return &vtable; }
    static A_vtable::type *get(B*) { static type vtable; return &vtable; }
    static A_vtable::type *get(C*) { static type vtable; return &vtable; }

    class ptr
    {
      public:
        type * get()                     { return p_vtable;   }
        operator type*()                 { return get();      }
        type * operator ->()             { return get();      }

        void set (type * vtable)         { p_vtable = vtable; }
        void operator () (type * vtable) { set(vtable);       }

      private:
        A_vtable::type * p_vtable;
     };
//------------------------------------------------------------------------------
};

class A // абстрактный
{
        friend class __A;
  public:
        A() { A_vtable_ptr(A_vtable::get(this)); }

  private:
        void priv_fn() { cout << "  A::private_function()" ; }

  private:
// pseudo-virtual-implementation
// отсутствует в абстракном классе

  public:
// pseudo-virtual-interface -
        void f1()      { (*A_vtable_ptr).f1(this); }
        void f2(int i) { (*A_vtable_ptr).f2(this, i); }
        void f3(int i) { (*A_vtable_ptr).f3(this, i); }

   protected:
        A_vtable::ptr A_vtable_ptr;
};

class B: public A
{
        friend class __B;
  public:
        B() { A_vtable_ptr(A_vtable::get(this)); }

  private:
        void priv_fn() { cout << "  B::private_function()" ; }

  private:
// pseudo-virtual-implementation
        void vf1()       { cout << "B::f1();" << endl; };
        void vf2(int i)  { cout << "B::f2(int) {";   priv_fn();  cout <<"; };"<< endl;  };
        void vf3(int i)  { cout << "B::f3(int);" << endl; };

};

class C : public B
{
        friend class __C;
 public:
        C() {  A_vtable_ptr(A_vtable::get(this));  }

 private:
        void priv_fn() { cout << "  C::private_function()" ; }

 private:
// pseudo-virtual-implementation
        void vf1()       { cout << "C::f1();" << endl; };
        void vf2(int i)  { cout << "C::f2(int);" << endl; };
        void vf3(int i)  { cout << "C::f3(int) {"; priv_fn(); cout <<"; };"<< endl; };
};

// Helpers ----------------------------------------------------------------------
// обслуживание виртуального механизма:

// ниже использован #define - но должен быть шаблон
#define A_VTABLE_INIT_PROC(Name, Class) public: static void Name() { \
                                 A_vtable::get((Class*)NULL)->f1=&__##Class::__vf1; \
                                 A_vtable::get((Class*)NULL)->f2=&__##Class::__vf2; \
                                 A_vtable::get((Class*)NULL)->f3=&__##Class::__vf3; };

class __A
{
  protected:
        static void __on_abstract_call () { cout << "exception:: abstract method" << endl;  }

  protected:
        static void __vf1(void* __this)         { __on_abstract_call (); };
        static void __vf2(void* __this, int i)  { __on_abstract_call (); };
        static void __vf3(void* __this, int i)  { __on_abstract_call (); };

        A_VTABLE_INIT_PROC(__init,A)

};

class __B: protected __A
{
  private:
        static void __vf1(void* __this)         { (reinterpret_cast<B*>(__this))->vf1();  };
        static void __vf2(void* __this, int i)  { (reinterpret_cast<B*>(__this))->vf2(i); };

        A_VTABLE_INIT_PROC(__init,B)
};

class __C: protected __B
{
  private:
        static void __vf1(void* __this)         { (reinterpret_cast<C*>(__this))->vf1();  };
        static void __vf2(void* __this, int i)  { (reinterpret_cast<C*>(__this))->vf2(i); };
        static void __vf3(void* __this, int i)  { (reinterpret_cast<C*>(__this))->vf3(i); };

        A_VTABLE_INIT_PROC(__init,C)

};
#undef A_VTABLE_INIT_PROC
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------

void test_virtual (A* pa)
{
    pa->f1();
    pa->f2(4);
    pa->f3(5);
};

int main(int argc, char *argv[])
{
    __A::__init ();
    __B::__init ();
    __C::__init ();

    cout <<endl;

    A *pa;

    pa = new A();
      test_virtual(pa);
    delete pa;

    cout <<endl;

    pa = new B();
      test_virtual(pa);
    delete pa;

    cout <<endl;

    pa = new C();
      test_virtual(pa);
    delete pa;

    cout <<endl;

    system("PAUSE");
    return EXIT_SUCCESS;
}


Это сообщение отредактировал(а) mes - 24.5.2008, 20:39


--------------------
PM MAIL WWW   Вверх
mes
Дата 24.5.2008, 23:00 (ссылка) |   (голосов:2) Загрузка ... Загрузка ... Быстрая цитата Цитата


любитель
****


Профиль
Группа: Участник Клуба
Сообщений: 7954
Регистрация: 14.1.2006

Репутация: 144
Всего: 250



Ну вот дошли и до извращений .
Специально для любителей таких вещей :

main.cpp :
Код

#include <cstdlib>
#include <iostream>

using namespace std;

#define VIRTUAL_ILLUSTRATION

#ifdef VIRTUAL_ILLUSTRATION

#define PASSED_PROMPT(instruction) /* instruction */
#define SPECIFIC_NAME(Name) interior_name_##Name
#define INTERIOR(a) a

#else

#define PASSED_PROMPT(instruction)  instruction
#define SPECIFIC_NAME(Name) Name
#define INTERIOR(a) /* a */

#endif

// PASSED_PROMPT     - показывает какая инструкция должна быть в реальном случае
// SPECIFIC_NAME     - внутреннее имя используемое компилятором
// INTERIOR(a)       - иллюстрация внутреннего компиляторного кода


INTERIOR( void SPECIFIC_NAME(on_abstract_call) () { cout << "exception:: abstract method" << endl;  } )

//------------------------------------------------------------------------------
// предопределения построенные компилятором для виртуальной таблицы A_vtable

class A;
class B;
class C;

INTERIOR
(           namespace A_vtable
            {  struct type;

               type *get(A*);
               type *get(B*);
               type *get(C*);

              class ptr
              {
                  public:
                    type * get()                     { return p_vtable;   }
                    operator type*()                 { return get();      }
                    type * operator ->()             { return get();      }

                    void set (type * vtable)         { p_vtable = vtable; }
                    void operator () (type * vtable) { set(vtable);       }

                  private:
                    A_vtable::type * p_vtable;
               };
            };
)
//------------------------------------------------------------------------------

class A // абстрактный
{
        friend class __A;
  public:
        A() { INTERIOR( init_virtual(); ) }

  private:
        void priv_fn() { cout << "  A::private_function()" ; }

  private:

// virtual implementation отсутствует в pure abstract классе

  public:

    PASSED_PROMPT( virtual ) void f1()      PASSED_PROMPT( =0 );
    PASSED_PROMPT( virtual ) void f2(int i) PASSED_PROMPT( =0 );
    PASSED_PROMPT( virtual ) void f3(int i) PASSED_PROMPT( =0 );

    INTERIOR(  protected: A_vtable::ptr A_vtable_ptr; )
    INTERIOR(  private: void init_virtual (); )
};

//------------------------------------------------------------------------------

class B: public A
{
        friend class __B;
  public:
        B() { INTERIOR( init_virtual(); )}

  private:
        void priv_fn() { cout << "  B::private_function()" ; }

  private:
       void SPECIFIC_NAME(f1) ()       { cout << "B::f1();" << endl; };
       void SPECIFIC_NAME(f2) (int i)  { cout << "B::f2(int) {";   priv_fn();  cout <<"; };"<< endl;  };
//       void SPECIFIC_NAME(f3) (int i)  { cout << "B::f3(int);" << endl; };

       INTERIOR(  private: void init_virtual (); )
};

//------------------------------------------------------------------------------

class C : public B
{
        friend class __C;
   public:
        C() {  INTERIOR( init_virtual(); ) }

   private:
        void priv_fn() { cout << "  C::private_function()" ; }

   private:
       void SPECIFIC_NAME(f1) ()       { cout << "C::f1();" << endl; };
       void SPECIFIC_NAME(f2) (int i)  { cout << "C::f2(int);" << endl; };
       void SPECIFIC_NAME(f3) (int i)  { cout << "C::f3(int) {"; priv_fn(); cout <<"; };"<< endl; };

       INTERIOR(  private: void init_virtual (); )
};

//------------------------------------------------------------------------------
#ifdef VIRTUAL_ILLUSTRATION

#include "A_vtable.h" // INTERIOR

#endif
//------------------------------------------------------------------------------

void test_virtual (A* pa)
{
    pa->f1();
    pa->f2(4);
    pa->f3(5);
};

int main(int argc, char *argv[])
{
INTERIOR( __A::__init (); );
INTERIOR( __B::__init (); );
INTERIOR( __C::__init (); );

    cout <<endl;

    A *pa;

#ifdef VIRTUAL_ILLUSTRATION
    pa = new A();
    cout << "new A" << endl;

      test_virtual(pa);

    cout << "delete A" << endl;
    delete pa;
#else
    cout << "Can't create A because it has abstract method " << endl;
#endif

    cout <<endl;

#ifdef VIRTUAL_ILLUSTRATION
    pa = new B();
    cout << "new B" << endl;

      test_virtual(pa);

    cout << "delete B" << endl;
    delete pa;
#else
    cout << "Can't create B because it has abstract method " << endl;
#endif

    cout <<endl;

    pa = new C();
    cout << "new C;" << endl;

      test_virtual(pa);

    cout << "delete C" << endl;
    delete pa;

    cout <<endl;

    system("PAUSE");
    return EXIT_SUCCESS;
}


A_vtable.h :
Код


// обслуживание виртуального механизма: ----------------------------------------

#define A_VTABLE_INIT_PROC(Name, Class) public: static void Name() { \
                                 A_vtable::get((Class*)NULL)->f1=&__##Class::SPECIFIC_NAME(f1); \
                                 A_vtable::get((Class*)NULL)->f2=&__##Class::SPECIFIC_NAME(f2); \
                                 A_vtable::get((Class*)NULL)->f3=&__##Class::SPECIFIC_NAME(f3); };



namespace A_vtable
{
    struct type
    {
        void (*f1)(void* __this);
        void (*f2)(void* __this, int i);
        void (*f3)(void* __this, int i);
    };
};

// ниже использован #define - но должен быть шаблон


extern void SPECIFIC_NAME(on_abstract_call) ();
class __A
{
  protected:


  protected:
        static void SPECIFIC_NAME(f1)(void* __this)         { SPECIFIC_NAME (on_abstract_call)(); };
        static void SPECIFIC_NAME(f2)(void* __this, int i)  { SPECIFIC_NAME (on_abstract_call)(); };
        static void SPECIFIC_NAME(f3)(void* __this, int i)  { SPECIFIC_NAME (on_abstract_call)(); };

        A_VTABLE_INIT_PROC(__init,A)

};

class __B: protected __A
{
  private:
        static void SPECIFIC_NAME(f1)(void* __this)         { (reinterpret_cast<B*>(__this))->SPECIFIC_NAME(f1)();  };
        static void SPECIFIC_NAME(f2)(void* __this, int i)  { (reinterpret_cast<B*>(__this))->SPECIFIC_NAME(f2)(i); };

        A_VTABLE_INIT_PROC(__init,B)
};

class __C: protected __B
{
  private:
        static void SPECIFIC_NAME(f1)(void* __this)         { (reinterpret_cast<C*>(__this))->SPECIFIC_NAME(f1)();  };
        static void SPECIFIC_NAME(f2)(void* __this, int i)  { (reinterpret_cast<C*>(__this))->SPECIFIC_NAME(f2)(i); };
        static void SPECIFIC_NAME(f3)(void* __this, int i)  { (reinterpret_cast<C*>(__this))->SPECIFIC_NAME(f3)(i); };

        A_VTABLE_INIT_PROC(__init,C)

};
#undef A_VTABLE_INIT_PROC

//------------------------------------------------------------------------------

void A::f1()      { (*A_vtable_ptr).f1(this); }
void A::f2(int i) { (*A_vtable_ptr).f2(this, i); }
void A::f3(int i) { (*A_vtable_ptr).f3(this, i); }

void A::init_virtual() { A_vtable_ptr(A_vtable::get(this)); }
void B::init_virtual() { A_vtable_ptr(A_vtable::get(this)); }
void C::init_virtual() { A_vtable_ptr(A_vtable::get(this)); }

A_vtable::type *A_vtable::get(A*) { static type vtable; return &vtable; }
A_vtable::type *A_vtable::get(B*) { static type vtable; return &vtable; }
A_vtable::type *A_vtable::get(C*) { static type vtable; return &vtable; }

//------------------------------------------------------------------------------



теперь  есть возможность "переключать" код между режимами (за/раскомментировать строку #define VIRTUAL_ILLUSTRATION ) :
1. реальные виртуальные методы
2. псевдо виртуальные методы (реализованые вручную (без помощи)  компилятора )

Хотя реальной пользы от программы нет - мне кажется он может помочь понять механизм работы виртуальных методв (у тех у кого проблемы)
теперь весь код псевдо производимый компилятором выделен и можно пронаблюдать различия и увидеть сколько черной работы
он(компилятор) делает за программиста.






Это сообщение отредактировал(а) mes - 24.5.2008, 23:08


--------------------
PM MAIL WWW   Вверх
xvr
Дата 25.5.2008, 10:32 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Комодератор
Сообщений: 7046
Регистрация: 28.8.2007
Где: Дублин, Ирландия

Репутация: 60
Всего: 223



Цитата(mes @ 24.5.2008,  23:00)
Ну вот дошли и до извращений .
Специально для любителей таких вещей :

Круто  smile С реальной реализацией в компиляторе есть только одно отличие - компилятор строит таблицы виртуальных функций статически (без метода __init) и располагает их каждую в своем классе (а не все в самом базовом).
Предлагаю в качестве дальнейших шагов рассмотреть множественное наследование, виртуальные базовые классы и RTTI/dynamic_cast  smile 

PS. Предлагаю предыдущий пост поместить в FAQ.


Это сообщение отредактировал(а) xvr - 25.5.2008, 10:36
PM MAIL   Вверх
mes
Дата 25.5.2008, 12:16 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


любитель
****


Профиль
Группа: Участник Клуба
Сообщений: 7954
Регистрация: 14.1.2006

Репутация: 144
Всего: 250



Цитата(xvr @  25.5.2008,  10:32 Найти цитируемый пост)
компилятор строит таблицы виртуальных функций статически (без метода __init) 

учел замечания и убрал лишнее. буду рад комментам 
Код


#include <cstdlib>
#include <iostream>

#define VIRTUAL_ILLUSTRATION

#ifdef VIRTUAL_ILLUSTRATION

#define ___V(instruction) /* instruction */
#define ___(Name) interior_name_##Name
#define ___INTERIOR_V___(a) a

#else

#define ___V(instruction)  instruction
#define ___(Name) Name
#define ___INTERIOR_V___(a) /* a */

#endif

// ___V     - показывает какая инструкция должна быть в реальном случае
// ___     - внутреннее имя используемое компилятором
// ___INTERIOR_V___(a)       - иллюстрация внутреннего компиляторного кода

___INTERIOR_V___( void ___(on_abstract_call) () { std::cout << "exception:: abstract method" << std::endl;  } )

////////////////////////////////////////////////////////////////////////////////
// общие конструкции для виртуального механизма --------------------------------

#define DEFINE_VTABLE_PTR_WRAPPER(Class, type )     class Class \
               {                                                               \
                  public:                                                      \
                    type * get()                     { return p_vtable;   }    \
                    operator type*()                 { return get();      }    \
                    type * operator ->()             { return get();      }    \
                    void set (type * vtable)         { p_vtable = vtable; }    \
                    void operator () (type * vtable) { set(vtable);       }    \
                  private:                                                     \
                    type * p_vtable;                                           \
               };
//------------------------------------------------------------------------------
////////////////////////////////////////////////////////////////////////////////


////////////////////////////////////////////////////////////////////////////////
// базовая конструкция виртуального механизма класса А (и его потомков): -------

#define DEFINE_CONCRETE_A_VTABLE(Class)   private: \
               struct ___(A_vtable_concrete): public ___(A_vtable)::type     \
               { ___(A_vtable_concrete())                                              \
                                    { f1=&Class::___(f1);                              \
                                      f2=&Class::___(f2);                              \
                                      f3=&Class::___(f3);                              \
                                    };                                                           \
               };                                                                                \
               public: static ___(A_vtable_concrete)* ___(GetConcrete_A_vtable) () \
                                            { static ___(A_vtable_concrete) vtable; return &vtable; }

  ___INTERIOR_V___
  (
         namespace ___(A_vtable)
         {
               struct type
               {
                    void (*f1)(void* __this);
                    void (*f2)(void* __this, int i);
                    void (*f3)(void* __this, int i);
               };

               DEFINE_VTABLE_PTR_WRAPPER(ptr, type);
          };
  )
//------------------------------------------------------------------------------
////////////////////////////////////////////////////////////////////////////////


class A // абстрактный
{
  public:
        A() { ___INTERIOR_V___( ___(init_vtable_ptr)(); ) }

  public:

    ___V( virtual ) void f1()      ___V( =0 );
    ___V( virtual ) void f2(int i) ___V( =0 );
    ___V( virtual ) void f3(int i) ___V( =0 );

  private:
        void priv_fn() { std::cout << "  A::private_function()" ; }

  private:

// virtual implementation отсутствует в pure abstract классе

  ___INTERIOR_V___
  (

      protected:
            static void ___(f1)(void* __this)         { ___(on_abstract_call)(); };
            static void ___(f2)(void* __this, int i)  { ___(on_abstract_call)(); };
            static void ___(f3)(void* __this, int i)  { ___(on_abstract_call)(); };

      protected:
            ___(A_vtable)::ptr ___(A_vtable_ptr);
      private:
            void ___(init_vtable_ptr) ();

            DEFINE_CONCRETE_A_VTABLE(A)
  )
};

//------------------------------------------------------------------------------

class B: public A
{
  public:
        B() { ___INTERIOR_V___( ___(init_vtable_ptr)(); )}

  private:
        void priv_fn() { std::cout << "  B::private_function()" ; }

  private:
       void ___(f1) ()       { std::cout << "B::f1();" << std::endl; };
       void ___(f2) (int i)  { std::cout << "B::f2(int) {";   priv_fn();  std::cout <<"; };"<< std::endl;  };
//     void ___(f3) (int i)  { std::cout << "B::f3(int);" << std::endl; }; // не перегруженая виртуальная функция


  ___INTERIOR_V___
  (

      protected:
        static void ___(f1)(void* __this)         { (reinterpret_cast<B*>(__this))->___(f1)();  };
        static void ___(f2)(void* __this, int i)  { (reinterpret_cast<B*>(__this))->___(f2)(i); };
//      static void ___(f3)(void* __this, int i)  { (reinterpret_cast<B*>(__this))->___(f3)(i); };

      private:
            void ___(init_vtable_ptr) ();

            DEFINE_CONCRETE_A_VTABLE(B)
  )

};

//------------------------------------------------------------------------------

class C : public B
{
   public:
        C() {  ___INTERIOR_V___( ___(init_vtable_ptr)(); ) }

   private:
        void priv_fn() { std::cout << "  C::private_function()" ; }

   private:
       void ___(f1) ()       { std::cout << "C::f1();" << std::endl; };
       void ___(f2) (int i)  { std::cout << "C::f2(int);" << std::endl; };
       void ___(f3) (int i)  { std::cout << "C::f3(int) {"; priv_fn(); std::cout <<"; };"<< std::endl; };

  ___INTERIOR_V___
  (

      protected:
        static void ___(f1)(void* __this)         { (reinterpret_cast<C*>(__this))->___(f1)();  };
        static void ___(f2)(void* __this, int i)  { (reinterpret_cast<C*>(__this))->___(f2)(i); };
        static void ___(f3)(void* __this, int i)  { (reinterpret_cast<C*>(__this))->___(f3)(i); };

      private:
            void ___(init_vtable_ptr) ();

            DEFINE_CONCRETE_A_VTABLE(C)
  )
};

////////////////////////////////////////////////////////////////////////////////
// связывание виртуального механизма : -----------------------------------------
  ___INTERIOR_V___
  (
        void A::f1()      { ___(A_vtable_ptr) -> f1(this); }
        void A::f2(int i) { ___(A_vtable_ptr) -> f2(this, i); }
        void A::f3(int i) { ___(A_vtable_ptr) -> f3(this, i); }

        void A::___(init_vtable_ptr)() { ___(A_vtable_ptr) .set( ___(GetConcrete_A_vtable)() ); }
        void B::___(init_vtable_ptr)() { ___(A_vtable_ptr) .set( ___(GetConcrete_A_vtable)() ); }
        void C::___(init_vtable_ptr)() { ___(A_vtable_ptr) .set( ___(GetConcrete_A_vtable)() ); }

   )
//------------------------------------------------------------------------------
////////////////////////////////////////////////////////////////////////////////

void test_virtual (A* pa)
{
    pa->f1();
    pa->f2(4);
    pa->f3(5);
};
////////////////////////////////////////////////////////////////////////////////
// MAIN ------------------------------------------------------------------------

int main(int argc, char *argv[])
{

#ifdef VIRTUAL_ILLUSTRATION
    std::cout << "/* illustration-mode: */" <<std::endl;
#else
    std::cout << "/* real-mode: */" <<std::endl;
#endif

    std::cout <<std::endl;

    A *pa;

#ifdef VIRTUAL_ILLUSTRATION
    pa = new A();
    std::cout << "new A" << std::endl;

      test_virtual(pa);

    std::cout << "delete A" << std::endl;
    delete pa;
#else
    std::cout << "Can't create A because it has abstract method " << std::endl;
#endif

    std::cout <<std::endl;

#ifdef VIRTUAL_ILLUSTRATION
    pa = new B();
    std::cout << "new B" << std::endl;

      test_virtual(pa);

    std::cout << "delete B" << std::endl;
    delete pa;
#else
    std::cout << "Can't create B because it has abstract method " << std::endl;
#endif

    std::cout <<std::endl;

    pa = new C();
    std::cout << "new C" << std::endl;

      test_virtual(pa);

    std::cout << "delete C" << std::endl;
    delete pa;

    std::cout <<std::endl;

    system("PAUSE");
    return EXIT_SUCCESS;
}

//------------------------------------------------------------------------------
////////////////////////////////////////////////////////////////////////////////





Цитата(xvr @  25.5.2008,  10:32 Найти цитируемый пост)
Предлагаю в качестве дальнейших шагов рассмотреть множественное наследование, виртуальные базовые классы и RTTI/dynamic_cast 

надо будет подумать ( когда будет свободное время )

Это сообщение отредактировал(а) mes - 25.5.2008, 15:56


--------------------
PM MAIL WWW   Вверх
xvr
Дата 25.5.2008, 20:12 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Комодератор
Сообщений: 7046
Регистрация: 28.8.2007
Где: Дублин, Ирландия

Репутация: 60
Всего: 223



Цитата(mes @ 25.5.2008,  12:16)
Цитата(xvr @  25.5.2008,  10:32 Найти цитируемый пост)
компилятор строит таблицы виртуальных функций статически (без метода __init) 

учел замечания и убрал лишнее. буду рад комментам 

Коментарий: способ оформления таблицы виртуальных функций (как это делает компилятор)
Код

struct vtable_type
{
  void (*f1)(void* __this);
  void (*f2)(void* __this, int i);
  void (*f3)(void* __this, int i);
};

class A // абстрактный
{
  public:
        A();

  public:

    ___V( virtual ) void f1()      ___V( =0 );
    ___V( virtual ) void f2(int i) ___V( =0 );
    ___V( virtual ) void f3(int i) ___V( =0 );

  private:
        void priv_fn() { std::cout << "  A::private_function()" ; }

  private:

// virtual implementation отсутствует в pure abstract классе

  ___INTERIOR_V___
  (

      protected:
            static void ___(f1)(void* __this)         { ___(on_abstract_call)(); };
            static void ___(f2)(void* __this, int i)  { ___(on_abstract_call)(); };
            static void ___(f3)(void* __this, int i)  { ___(on_abstract_call)(); };

      protected:
            ___(A_vtable)::ptr ___(A_vtable_ptr);
  )
};

static vtable_type vtable_classA = {&A::___(f1),&A::___(f2),&A::___(f3)};

A::A() {A_vtable_ptr=&vtable_classA;}


т.е. какой либо код для построения таблицы виртуальных функций отсуствует вообще, только присваивание адреса в конструкторе

PM MAIL   Вверх
mes
Дата 25.5.2008, 20:56 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


любитель
****


Профиль
Группа: Участник Клуба
Сообщений: 7954
Регистрация: 14.1.2006

Репутация: 144
Всего: 250



Цитата(xvr @  25.5.2008,  20:12 Найти цитируемый пост)
т.е. какой либо код для построения таблицы виртуальных функций отсуствует вообще, только присваивание адреса в конструкторе


то есть разница что компилятор строит ее в компил-тайм, а в моем примере в рантайме ?
ну так оно и есть:
в одном случае таблица строится управляемая инструкциями типа virtual во время парсинга кода
во втором строится за счет рант-тайм кода конструкторов

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

 


--------------------
PM MAIL WWW   Вверх
Страницы: (3) Все 1 [2] 3 
Ответ в темуСоздание новой темы Создание опроса
Правила форума "С++:Общие вопросы"
Earnest Daevaorn

Добро пожаловать!

  • Черновик стандарта C++ (за октябрь 2005) можно скачать с этого сайта. Прямая ссылка на файл черновика(4.4мб).
  • Черновик стандарта C (за сентябрь 2005) можно скачать с этого сайта. Прямая ссылка на файл черновика (3.4мб).
  • Прежде чем задать вопрос, прочтите это и/или это!
  • Здесь хранится весь мировой запас ссылок на документы, связанные с C++ :)
  • Не брезгуйте пользоваться тегами [code=cpp][/code].
  • Пожалуйста, не просите написать за вас программы в этом разделе - для этого существует "Центр Помощи".
  • C++ FAQ

Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, Earnest Daevaorn

 
1 Пользователей читают эту тему (1 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | C/C++: Общие вопросы | Следующая тема »


 




[ Время генерации скрипта: 0.1235 ]   [ Использовано запросов: 21 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.