function factorial(n) {
return n == 0 ? 1 : n * factorial(n - 1);
}
Давайте проведем рефакторинг и создадим новую функцию под названием fact
, которая вместо выполнения самого вычисления возвращает анонимную функцию факториального вычисления:
function fact() {
return function(n) {
return n == 0 ? 1 : n * fact()(n - 1);
};
}
var factorial = fact();
Это немного странно, но в этом нет ничего плохого. Мы просто генерируем новую факториальную функцию на каждом шаге.
Рекурсия на этом этапе все еще довольно явно. Функция fact
должна знать свое имя. Давайте параметризуем рекурсивный вызов:
function fact(recurse) {
return function(n) {
return n == 0 ? 1 : n * recurse(n - 1);
};
}
function recurser(x) {
return fact(recurser)(x);
}
var factorial = fact(recurser);
Это здорово, но recurser
все еще нужно знать его собственное имя. Давайте также параметризуем это:
function recurser(f) {
return fact(function(x) {
return f(f)(x);
});
}
var factorial = recurser(recurser);
Теперь, вместо непосредственного вызова recurser(recurser)
, давайте создадим функцию-обертку, которая возвращает ее результат:
function Y() {
return (function(f) {
return f(f);
})(recurser);
}
var factorial = Y();
Теперь мы можем избавиться от recurser
имя в целом; это просто аргумент внутренней функции Y, который можно заменить самой функцией:
function Y() {
return (function(f) {
return f(f);
})(function(f) {
return fact(function(x) {
return f(f)(x);
});
});
}
var factorial = Y();
Единственное внешнее имя, на которое все еще ссылаются, это fact
, но теперь должно быть ясно, что это легко параметризовать, также, создавая полное, общее решение:
function Y(le) {
return (function(f) {
return f(f);
})(function(f) {
return le(function(x) {
return f(f)(x);
});
});
}
var factorial = Y(function(recurse) {
return function(n) {
return n == 0 ? 1 : n * recurse(n - 1);
};
});
Я не думал, что вы можете рассчитывать на совместимость любых построенных классов между компиляторами. Утверждает ли Borland, что они могут загружать классы, созданные MSVC, и взаимодействовать с ними. Если так, похоже, у них есть ошибка. Насколько мне известно, ничего о точной структуре VTable не указано в спецификации C ++, поэтому не ожидается, что она будет работать во всех компиляторах.
Я с подозрением отношусь к аргументу void **
. Использование указателей void приводит к потере информации о типе.
Если вы работаете с множественным наследованием, информация о типе может быть важной. Рассмотрим:
class Foo { ... };
class Bar { ... };
class Both: public Foo, public Bar { ... };
Предположим, что внутренняя структура экземпляра Both - это экземпляр Foo, за которым следует экземпляр Bar. Я могу без проблем передать Both * методу, ожидающему Foo *. Я также могу передать Both * методу, ожидающему Bar *, при условии, что я настрою указатель так, чтобы он указывал на встроенную Bar. Я могу сделать это надежно, потому что я знаю, что работаю с обоими.
Теперь:
Foo *foo = new Both(...);
Bar *bar = new Both(...);
void *p = foo;
void *q = bar;
Both *both = (which) ? (Both*)p : (Both*)q;
Итак: как мне узнать, как настроить либо p, либо q, когда я назначаю «оба»? Я не могу, потому что информация о типе теряется при прохождении указателя void.
Вариант этой проблемы может быть связан с вашими проблемами.
Наверное, не ответит на ваш вопрос ... Но настоятельно рекомендуется НЕ использовать множественное наследование, как вы это делаете (так называемый «ужасный алмаз»).
В отличие от C, для C ++ отсутствует кросс-компиляторный ABI - компиляторы могут реализовать виртуальное наследование (и даже обычное наследование) любым способом.
В результате: вызов функций C ++ через компиляторы не гарантируется. Я знаю, что это некрасиво, но если вы хотите, чтобы ваша DLL успешно взаимодействовала с несколькими компиляторами, вам, вероятно, лучше предоставить набор простых extern «C»
функций и составленные вручную таблицы указателей функций.
Примечание. Компиляторы, которые поддерживают создание COM-объектов (или имеют возможность делать это), имеют более ограниченные возможности в своих макетах объектов. (Я знаю, что последние версии MSVC ++ создают COM-совместимые объекты, по крайней мере, в большинстве случаев - хотя я не уверен, распространяется ли виртуальное наследование.)