Уважаемый сэр!
я должен сказать Вам что, что я знаю и что я не знаю о заданном вопросе так, чтобы можно было обратиться к слабой области моего понимания.
я знаю, что C++ реализует полиморфизм при помощи Vtable, который является массивом указателей, на которые каждый указатель указывает на виртуальную функцию класса, каждый класс в иерархии имеет vtable. теперь предположите, что у меня есть следующий класс
class person
{
char name[20];
public:
person(char* pname)
{
strcpy(name,pname);
}
virtual void show()
{
cout<<"inside person show method, Name: "<<name;
}
};
class teacher:public person
{
int scale;
teacher(char*pname, int s):person(pname)
{
scale=s;
}
void show()
{
cout<<"inside the teacher show method, Scale: "<<scale;
}
};
теперь предположите, что я пишу в основной программе
person *ptr;
ptr=new teacher(16,"Zia");
ptr->show();
теперь я, путают в этой точке, вызов перейдет к выставочной функции базового класса, теперь поскольку это - виртуальная функция так это, внутренний изгиб вызывает approprite функцию. я знаю, что я неправ здесь. я смущен это, что было бы последовательностью вызовов. Что является ролью Vtable и как это работает, уточните.
Я думаю, что вы должны обратить внимание на книгу Стэнли Б. Липпмана » внутри объектной модели C ++ ».
Давайте посмотрим на внутреннюю презентацию для ваших классов:
Виртуальная таблица для человека и учителя
|---------------| +---> |------------------------|
| name | | | "type_info" for person |
|---------------| | |------------------------|
|__vptr__person |--+ | "person::~person" |
|---------------| |------------------------|
person p; | "person::show" |
|------------------------|
|----------------| +---> |-------------------------|
|person subobject| | | "type_info" for teacher |
|----------------| | |-------------------------|
|__vptr__teacher |--+ | "teacher::~teacher" |
|----------------| |-------------------------|
teacher t; | "teacher::show" |
|-------------------------|
В целом мы не знаем точный тип адресов объекта PTR при каждом вызове Show (). Однако мы знаем, что через PTR мы можем получить доступ к виртуальной таблице, связанной с классом объекта.
Хотя мы не знаем, какой экземпляр Show (), чтобы вызвать, мы знаем, что адрес каждого экземпляра содержится в слоте 2.
Эта информация позволяет компилятору внутренне преобразовывать вызов
( *ptr->vptr[ 2 ] )( ptr );
в этом преобразовании. , VPTR представляет собой внутренне генерируемую указатель виртуальной таблицы, вставленный в каждом классном объекте, а 2 представляет собой показывать () назначенный слот в виртуальной таблице, связанной с точкой иерархией. Единственное, что нам нужно сделать во время выполнения, вычисляет динамический тип PTR (и соответствующим VTable) с использованием RTTI.
В стандарте ничего не сказано о том, как реализовывать полиморфизм. Один класс один vtbl и один объект один vptr - самый популярный способ. Надеюсь, следующий псевдокод будет полезен.
typedef struct {
void (*show)(void* self);
// more
} person_vtbl;
typedef struct {
person_vtbl* vtbl;
char name[20];
} person;
void person_show(void* self) {
cout<<"inside ... "<<static_cast<person*>(self)->name;
}
// more
static person_vtbl person_vtbl_ = { &person_show }; // vtbl for person class
void person_ctor(void* self, char const* name) {
person* p = static_cast<person*>(self);
strcpy(p->name, name);
p->vtbl = &person_vtbl // vptr of person object
}
typedef struct {
person base;
int scale;
} teacher;
void teacher_show(void* self) {
cout<<"inside the tearch ... "<<static_cast<teacher*>(self)->scale;
}
static person_vtbl teacher_vtbl_ = { &teacher_show };
void teacher_ctor(void* self, char const* name, int s) {
teacher* t = static_cast<teacher*>(self);
person_ctor(&t->base, name); // construct base part
t->scale = s; // construct teacher part
t->vtbl = &teacher_vtbl_; // vptr of teacher object
}
// construct teacher :
// person* ptr = new teacher("Zia", 16);
teacher* tmp = static_cast<teacher*>( malloc( sizeof *tmp );
teacher_ctor(tmp, "Zia", 16); // vptr of tmp points to teacher_vtbl_
person* ptr = &tmp->base;
// call virtual function though pointer
// ptr->show()
ptr->vptr->show(ptr); // call teacher_show(ptr);
import re
title = re.sub("[\W\d]", "_", title.strip())
должно быть быстрее.
Если вы хотите заменить последовательность смежных букв, не являющихся буквами, одним подчеркиванием, используйте
title = re.sub("[\W\d]+", "_", title.strip())
, что еще быстрее.
Я только что провел сравнение времени:
C:\>python -m timeit -n 100 -s "data=open('test.txt').read().strip()" "''.join(map(lambda x: x if (x.isupper() or x.islower()) else '_', data))"
100 loops, best of 3: 4.51 msec per loop
C:\>python -m timeit -n 100 -s "import re; regex=re.compile('[\W\d]+'); data=open('test.txt').read().strip()" "title=regex.sub('_',data)"
100 loops, best of 3: 2.35 msec per loop
Это также будет работать на Юникод последовательностей (под Python 3, \W
соответствует любому символу, который не является символом слова Юникод. В разделе Python 2 необходимо дополнительно установить флаг UNICODE
).
Я обычно переключаюсь между режимом Makefile, текстовым режимом и режимом C в зависимости от того, в какой строке я участвую. Если вы хотите лучше, вы должны написать режим!
-121--1309628- Поскольку show
объявлен virtual
в классе person
, компилятор не будет жестко кодировать вызов метода так, как это было бы сделано для невиртуального метода, он вместо этого скомпилирует поиск в V-таблице, чтобы получить нужную функцию.
Поэтому ptr- > show ()
будет скомпилирован как ptr- > vtable ['show'] ()
, что означает «поиск указателя функции, соответствующего методу show
, и его выполнение».
Поскольку во время выполнения ptr
точек к объекту класса teacher
, слот vtable для show
содержит указатель на метод show
в классе teacher
. Именно поэтому выполняется правильный метод.
На самом деле поиск в V-таблице выполняется не с использованием последовательностей, а с использованием числовых идентификаторов методов, чтобы быть максимально быстрым.
Язык C ++ не определяет реализации полиморфизма, даже vtable
. Это дело компиляторов.
Одна из возможных реализаций указана Винсентом Робертом .