C++ Builder
| Главная | Уроки | Статьи | FAQ | Форум | Downloads | Литература | Ссылки | RXLib | Диски |

 
Как в Билдере получить имя класса?, Тока речь не про VCL и не MFC :)
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++.
Подайте, кто может. smile.gif

Отредактировано 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



Это классная вещь. Я как-то пропустил. а может и не пропустил. smile.gif

Гонзольное приложение с исп. VCL (так получилось smile.gif )

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 (т.е. объекта, в котором он работает), он должен быть описан в классе этого объекта. Наследованная функция будет давать имя класса, который наследуется, а не потомка.
smile.gif

Тип this зависит от функции, в которой используется. Ну и фигня!
Чтобы запомнить имя класса в объекте, надо писать каждый раз конструктор, в котором
ClassName = typeid(this).name();
Потом посмотрев поле ClassName будем знать имя класса объекта.
Тогда проще (а может и нет) в этих конструкторах писать
ClassName = "TMyNewClass"; sad.gif


Отредактировано Deem — 18/01/2005, 16:30
Asher
Отправлено: 18.01.2005, 18:05


Мастер участка

Группа: Модератор
Сообщений: 550



Ну зачем сразу
QUOTE
Тип this зависит от функции, в которой используется. Ну и фигня!

а если так? cool.gif
CODE
virtual const char* GetName()
 {
  return typeid(*this).name();
 }


Отредактировано Asher — 18/01/2005, 20:10
Deem
Отправлено: 19.01.2005, 11:48


Мастер участка

Группа: Участник
Сообщений: 327



Ну, Asher, пробовал. Но тогда все равно в каждом классе надо эту функцию переопределить. smile.gif А классы 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. И еще: честно , не знал, что вирутальную функцию можно не переписывать для дочернего класса. smile.gif Родительская работает как переписанная. У меня они всегда отличались, поэтому обязательно переписывались. Короче, просветился основательно.



Отредактировано Deem — 21/01/2005, 15:43
Deem
Отправлено: 21.01.2005, 14:51


Мастер участка

Группа: Участник
Сообщений: 327



Ну а все таки, как тут быть (если, конеша, не надоело smile.gif ):

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 таки зависит от функции, а не от объекта. smile.gif
Конструктор виртуальным не сделаешь. Можно после создания объекта вызывать какой-нить виртуальный 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();

вроде все путем.

Вернуться в Вопросы программирования в C++Builder