Deem |
Отправлено: 18.01.2005, 11:42 |
|
Мастер участка
Группа: Участник
Сообщений: 327
|
Рылся я в system.pas, смотрел, как создается объект класса TObject... Но так и не понял, откуда он берет имя класса, чтобы его отложить в своих заначках. Как изначально, может от препроцессора или еще как? В си нашел предопределенный макрос __FUNC__, который превращается препроцессором в строку-имя функции. Если функция — метод, то Имя_класса::Имя_функции. Но тогда мне в каждый наследованный класс надо вставлять эту фигню. Проще в конструкторе вставлять ClassName = "TNewClass"; А в VCL имя класса определяется раз, для TObject. Для класса, унаследованного от любого VCL-класса я же не где не указываю имя класса, кроме как в определении class TMyClass : public TForm , к примеру. Однако после создания объекта моего класса метод ClassName() возвратит именно "TMyClass". И ClassName описан аж в TObject.
Я весь хелп перерыл и пару книжек, но не нашел варианта определения имени класса в C++.
Подайте, кто может.
Отредактировано Deem — 18/01/2005, 12:46
|
|
Asher |
Отправлено: 18.01.2005, 12:43 |
|
Мастер участка
Группа: Модератор
Сообщений: 550
|
Консольный проект
CODE | #pragma hdrstop
#include <iostream>
#include <fstream>
#include <typeinfo.h>
//---------------------------------------------------------------------------
class abc
{
int num;
};
//---------------------------------------------------------------------------
#pragma argsused
int main(int argc, char* argv[])
{
abc a;
abc* b = &a;
std::cout << typeid(abc).name()<<std::endl;
std::cout << typeid(a).name()<<std::endl;
std::cout << typeid(b).name()<<std::endl;
return 0;
}
//--------------------------------------------------------------------------- |
|
|
Deem |
Отправлено: 18.01.2005, 15:00 |
|
Мастер участка
Группа: Участник
Сообщений: 327
|
Это классная вещь. Я как-то пропустил. а может и не пропустил.
Гонзольное приложение с исп. VCL (так получилось )
CODE |
#include <iostream>
#include <conio.h>
#include <vcl.h>
#include <fstream>
#include <typeinfo.h>
//---------------------------------------------------------------------------
class abc
{
int num;
public:
const char* GetName()
{
return typeid(this).name();
}
};
class Newabs : public abc
{
public:
int a;
};
//---------------------------------------------------------------------------
#pragma argsused
int main(int argc, char* argv[])
{
abc a;
abc* b = &a;
std::cout << typeid(abc).name()<<std::endl;
std::cout << typeid(a).name()<<std::endl;
std::cout << typeid(B).name()<<std::endl;
std::cout << b->GetName()<<std::endl;
Newabs na;
std::cout << na.GetName()<<std::endl;
std::cout << typeid(na).name()<<std::endl;
a = na;
std::cout << a.GetName()<<std::endl;
std::cout << typeid(a).name()<<std::endl;
getch();
return 0;
}
|
Обратите внимание: это тип переменной. Не класс объекта. Т.е. чтобы метод мог узнать тип this (т.е. объекта, в котором он работает), он должен быть описан в классе этого объекта. Наследованная функция будет давать имя класса, который наследуется, а не потомка.
Тип this зависит от функции, в которой используется. Ну и фигня!
Чтобы запомнить имя класса в объекте, надо писать каждый раз конструктор, в котором
ClassName = typeid(this).name();
Потом посмотрев поле ClassName будем знать имя класса объекта.
Тогда проще (а может и нет) в этих конструкторах писать
ClassName = "TMyNewClass";
Отредактировано Deem — 18/01/2005, 16:30
|
|
Asher |
Отправлено: 18.01.2005, 18:05 |
|
Мастер участка
Группа: Модератор
Сообщений: 550
|
Ну зачем сразу
QUOTE | Тип this зависит от функции, в которой используется. Ну и фигня! |
а если так?
CODE | virtual const char* GetName()
{
return typeid(*this).name();
} |
Отредактировано Asher — 18/01/2005, 20:10
|
|
Deem |
Отправлено: 19.01.2005, 11:48 |
|
Мастер участка
Группа: Участник
Сообщений: 327
|
Ну, Asher, пробовал. Но тогда все равно в каждом классе надо эту функцию переопределить. А классы VCL в подобных мансах не нуждаются. Вот мне было интересно — как? Но в system.pas так и не увидел, где берется имя класса при создании объекта. Потом, когда объект создан, я знаю где лежит имя класса (даже без ClassName()). Но как оно туда попадает — не знаю. Знаю еще, что в ехе-файле даже без debuginfo лежат имена классов. Их в редакторе видать. Файл грузится в память, и наверное можно до них добраться. Попробую. Или же буду конструкторе всегда указывать.
Ну ладно, спасибо, кое-что я получил.
И тогда вот еще что: можно добраться до VMT ? Она — общая для программы, или для каждого класса?
Отредактировано Deem — 19/01/2005, 12:57
|
|
Asher |
Отправлено: 19.01.2005, 13:34 |
|
Мастер участка
Группа: Модератор
Сообщений: 550
|
Привет.
QUOTE | Но тогда все равно в каждом классе надо эту функцию переопределить. |
если все порождены от од одного базового — то нет.
Вот в этом примере в потомке ничего не переопределяется, но метод
GetName() выдает правильное имя класса объекта. в последнем абзаце вывода.
CODE | #include <iostream>
#include <fstream>
#include <typeinfo.h>
#include <conio.h>
#include <stdio.h>
//---------------------------------------------------------------------------
class A
{
public:
virtual const char* GetName()
{return typeid(*this).name();}
};
class B : public A
{
};
#pragma argsused
int main(int argc, char* argv[])
{
A a;
A* pa = &a;
std::cout << typeid(A).name() << std::endl;
std::cout << typeid(a).name() << std::endl;
std::cout << typeid(pa).name() << std::endl;
std::cout << a.GetName() << std::endl;
std::cout << pa->GetName() << std::endl;
std::cout << std::endl;
B b;
B* pb = &b;
std::cout << typeid(B).name() << std::endl;
std::cout << typeid(b).name() << std::endl;
std::cout << typeid(pb).name() << std::endl;
std::cout << b.GetName() << std::endl;
std::cout << pb->GetName() << std::endl;
std::cout << std::endl;
pa = pb;
std::cout << typeid(pa).name() << std::endl;
std::cout << pa->GetName() << std::endl;
getch();
return 0;
}
//--------------------------------------------------------------------------- |
|
|
Deem |
Отправлено: 21.01.2005, 14:35 |
|
Мастер участка
Группа: Участник
Сообщений: 327
|
Столько вариантов перепробывал, что потерял таки virtual. И еще: честно , не знал, что вирутальную функцию можно не переписывать для дочернего класса. Родительская работает как переписанная. У меня они всегда отличались, поэтому обязательно переписывались. Короче, просветился основательно.
Отредактировано Deem — 21/01/2005, 15:43
|
|
Deem |
Отправлено: 21.01.2005, 14:51 |
|
Мастер участка
Группа: Участник
Сообщений: 327
|
Ну а все таки, как тут быть (если, конеша, не надоело ):
CODE |
#include <iostream>
#include <fstream>
#include <typeinfo.h>
#include <conio.h>
#include <stdio.h>
//---------------------------------------------------------------------------
class A
{
public:
A()
{
std::cout << GetName() << std::endl;
}
const char* GetName()
{return typeid(*this).name();}
};
class B : public A
{
};
#pragma argsused
int main(int argc, char* argv[])
{
A a;
A* pa = &a;
B b;
B* pb = &b;
getch();
return 0;
}
|
Чтобы однажды написанный конструктор определял тиб объекта потомков? Тут GetName вызывается того класса, которого и конструктор. А тип this таки зависит от функции, а не от объекта.
Конструктор виртуальным не сделаешь. Можно после создания объекта вызывать какой-нить виртуальный Init. А жаль, что конструктор виртульный низя.
Отредактировано Deem — 21/01/2005, 15:58
|
|
Asher |
Отправлено: 21.01.2005, 16:56 |
|
Мастер участка
Группа: Модератор
Сообщений: 550
|
Привет.
Что-то я не пойму, что вы хотите получить.
Исходная задача, описанная в вашем первом посте решается кодом, приведенным мной 19/01/2005, 15:36.
Есть метод, который возвращает имя класса, метод описан только в предке. Вроде все как у Borland'а работает.
Или я чего-то не доглядел?
|
|
Deem |
Отправлено: 21.01.2005, 17:48 |
|
Мастер участка
Группа: Участник
Сообщений: 327
|
TObject и все его потомки запоминают имя класса в опред. область памяти (весь интерфейс там). Т.е. так как вышло, можно определить имя класса объекта извне. Это — нужная весч. Но наследованые методы не могут изнутри определить имя класса объекта, в котором в данный момент работают. Ладно, это уже и лишнее. Сперва я именно хотел извне определять имя класса объекта. Это работает.
|
|
Asher |
Отправлено: 21.01.2005, 18:41 |
|
Мастер участка
Группа: Модератор
Сообщений: 550
|
добавление к предыдущему примеру
CODE | class A
{
public:
virtual const char* GetName()
{return typeid(*this).name();}
void MethodA(void)
{std::cout <<"MethodA: " << GetName() << std::endl;}
};
class B : public A
{
public:
void MethodB(void)
{std::cout <<"MethodB: " << GetName() << std::endl;}
}; |
и в концеCODE | pa->MethodA();
pb->MethodB(); |
вроде все путем.
|
|