независимое от языка решение:
GIVEN: многоугольник может ВСЕГДА состоять из n-2 треугольников, которые не перекрываются (n = количество точек OR сторон). 1 треугольник = трехгранный многоугольник = 1 треугольник; 1 квадрат = 4-сторонний многоугольник = 2 треугольника; и т. д. ad nauseam QED
, поэтому многоугольник может быть уменьшен путем «измельчения» треугольников, а общая площадь будет суммой площадей этих треугольников. попробуйте его с помощью листка бумаги и ножниц, лучше всего, если вы представите процесс перед тем, как следовать.
, если вы возьмете любые 3 последовательные точки в пути многоугольников и создаете треугольник с этими точками, вы будете имеют один и только один из трех возможных сценариев:
, нас интересуют только случаи, которые попадают в первый вариант (полностью содержащийся).
каждый раз, когда мы находим один из них, мы прерываем его, вычисляем его площадь (легко peasy, не будем объяснять формулу здесь) и создаем новый многоугольник с одной меньшей стороной (эквивалентный полигону с этим треугольником, отрубленным ). пока мы не оставим только один треугольник.
как реализовать это программно:
создать массив (последовательных) точек, которые представляют путь ВОКРУГ многоугольника. начните в точке 0. запустите массив, создавая треугольники (по одному за раз) из точек x, x + 1 и x + 2. преобразуйте каждый треугольник из формы в область и пересечь его с областью, созданной из многоугольника. Если полученное пересечение идентично исходному треугольнику, то указанный треугольник полностью содержится в многоугольнике и может быть отрублен. удалите x + 1 из массива и начните снова с x = 0. в противном случае (если треугольник находится вне [частично или полностью] многоугольника), переходите к следующей точке x + 1 в массиве.
дополнительно, если вы хотите интегрироваться с отображением и начинать с геоинтеграции, вы должны преобразовать из геоинформации на экранные точки FIRST. это требует решения моделирования и формулы для формы земли (хотя мы склонны думать о Земле как о шаре, это на самом деле нерегулярная яйцевидная (яйцо) с вмятинами). существует много моделей, для получения дополнительной информации wiki. важная проблема заключается в том, считаете ли вы район плоской или изогнутой. в общем, «маленькие» области, где точки до нескольких километров друг от друга, не будут вызывать значительную ошибку, если рассматривать плоские и не выпуклые.
typedef void (Dog::*memfun)();
memfun doSomething = &Dog::bark;
....
(pDog->*doSomething)(); // if pDog is a pointer
// (pDog.*doSomething)(); // if pDog is a reference
Функциональный указатель на член класса - это проблема, которая действительно подходит для использования функции boost ::. Небольшой пример:
#include <boost/function.hpp>
#include <iostream>
class Dog
{
public:
Dog (int i) : tmp(i) {}
void bark ()
{
std::cout << "woof: " << tmp << std::endl;
}
private:
int tmp;
};
int main()
{
Dog* pDog1 = new Dog (1);
Dog* pDog2 = new Dog (2);
//BarkFunction pBark = &Dog::bark;
boost::function<void (Dog*)> f1 = &Dog::bark;
f1(pDog1);
f1(pDog2);
}
Минимальный пример runnable
#include <cassert>
class C {
public:
int i;
C(int i) : i(i) {}
int m(int j) { return this->i + j; }
};
int main() {
// Get a method pointer.
int (C::*p)(int) = &C::m;
// Create a test object.
C c(1);
C *cp = &c;
// Operator .*
assert((c.*p)(2) == 3);
// Operator ->*
assert((cp->*p)(2) == 3);
}
Вы не можете изменить порядок скобок или опустить их. Следующие не работают:
c.*p(2)
c.*(p)(2)
C ++ 11 standard
.*
и ->*
- сингенные операторы , введенные в C ++ для эта цель и не представлена в C.
C ++ 11 N3337 стандартная черновик :
.*
и ->*
. Чтобы создать новый объект, вы можете либо использовать новое место размещения, как упоминалось выше, либо реализовать свой метод clone (), создающий копию объекта. Затем вы можете вызвать этот метод clone с помощью указателя функции-члена, как описано выше, для создания новых экземпляров объекта. Преимущество клона заключается в том, что иногда вы можете работать с указателем на базовый класс, где вы не знаете тип объекта. В этом случае метод clone () может быть проще в использовании. Кроме того, clone () позволит вам скопировать состояние объекта, если это то, что вы хотите.
Я пришел сюда, чтобы узнать, как создать указатель на функцию (не указатель метода) из метода, но ни один из ответов здесь не дает решения. Поэтому я подумал об этом и нашел хорошее решение, которое, как мне кажется, стоит поделиться:
template <class T> struct MethodHelper;
template <class C, class Ret, class... Args> struct MethodHelper<Ret(C::*)(Args...)> {
using T = Ret (C::*)(Args...);
template <T m> static Ret call(C* object, Args... args) {
return (object->*m)(args...);
}
};
#define METHOD_FP(m) MethodHelper<decltype(m)>::call<m>
Итак, для вашего примера вы теперь выполните:
Dog dog;
using BarkFunction = void (*)(Dog*);
BarkFunction bark = METHOD_FP(&Dog::bark);
(*bark)(&dog); // or simply bark(&dog)
Как получить указатель на функцию для функции-члена класса, а затем вызвать эту функцию-член с определенным объектом?
blockquote>Легче всего начать с
typedef
, Для функции-члена вы добавляете имя класса в объявление типа:typedef void(Dog::*BarkFunction)(void);
Затем, чтобы вызвать метод, вы используете оператор
->*
:(pDog->*pBark)();
Кроме того, если это возможно, я хотел бы также вызвать конструктор с помощью указателя. Возможно ли это, и если да, то каков предпочтительный способ сделать это?
blockquote>Не думаю, что вы можете работать с такими конструкторами, как ctors и dtors. Обычный способ достижения такого рода вещей - использовать фабричный метод, который в основном представляет собой статическую функцию, которая вызывает конструктор для вас. Для примера см. Приведенный ниже код.
Я изменил ваш код, чтобы в основном описать то, что вы описали. Ниже приведены некоторые оговорки.
#include <iostream> class Animal { public: typedef Animal*(*NewAnimalFunction)(void); virtual void makeNoise() { std::cout << "M00f!" << std::endl; } }; class Dog : public Animal { public: typedef void(Dog::*BarkFunction)(void); typedef Dog*(*NewDogFunction)(void); Dog () {} static Dog* newDog() { return new Dog; } virtual void makeNoise () { std::cout << "Woof!" << std::endl; } }; int main(int argc, char* argv[]) { // Call member function via method pointer Dog* pDog = new Dog (); Dog::BarkFunction pBark = &Dog::makeNoise; (pDog->*pBark)(); // Construct instance via factory method Dog::NewDogFunction pNew = &Dog::newDog; Animal* pAnimal = (*pNew)(); pAnimal->makeNoise(); return 0; }
Теперь, хотя вы обычно можете использовать
Dog*
вместоAnimal*
благодаря магии полиморфизма, тип указателя функции делает не следуют правилам поиска иерархии классов. Таким образом, указатель метода Animal несовместим с указателем метода Dog, другими словами, вы не можете назначитьDog* (*)()
переменной типаAnimal* (*)()
.Статический метод
newDog
является простой пример фабрики, который просто создает и возвращает новые экземпляры. Будучи статической функцией, она имеет регулярныйtypedef
(без классификатора классов).Отвечая на вышеизложенное, я задаюсь вопросом, нет ли лучшего способа достижения того, что вам нужно. Есть несколько конкретных сценариев, в которых вы бы делали такие вещи, но вы можете обнаружить, что есть другие шаблоны, которые лучше работают для вашей проблемы. Если вы более подробно описываете то, чего пытаетесь достичь, улей-ум может оказаться еще более полезным!
В связи с вышеизложенным вы, несомненно, найдете Boost bind библиотека и другие связанные с ней модули очень полезны.
->*
, но теперь надеюсь, что мне это никогда не понадобится :)
– Thomas
28 September 2009 в 12:37
Причина, по которой вы не можете использовать указатели функций для вызова функций-членов, состоит в том, что обычные указатели функций обычно являются только адресом памяти функции.
Чтобы вызвать функцию-член, вам нужно знать две вещи:
Обычные указатели функций не могут хранить оба. Указатели функций элемента C ++ используются для хранения a), поэтому вам нужно явно указать экземпляр при вызове указателя функции-члена.
Я не думаю, что кто-то объяснил здесь, что одна проблема заключается в том, что вам нужны « указатели на элементы », а не обычные указатели функций.
Указатели элементов для функций не просто указатели функций. В условиях реализации компилятор не может использовать простой адрес функции, поскольку, как правило, вы не знаете адрес для вызова, пока не узнаете, к какому объекту относится к разыменованию (думать о виртуальных функциях). Вы также должны знать объект, чтобы, конечно, предоставить неявный параметр this
.
Сказав, что они вам нужны, теперь я скажу, что вам действительно нужно их избегать. Серьезно, указатели членов - это боль. Гораздо более разумно смотреть на объектно-ориентированные шаблоны проектирования, которые достигают той же цели, или использовать boost::function
или что-то еще, как упомянуто выше, - если вы сделаете этот выбор, то есть.
Если вы указали на эту функцию указатель на существующий код, вам действительно нужен простой указатель на функцию, вы должны написать функцию как статический член класса. Статическая функция-член не понимает this
, поэтому вам нужно передать объект в явном параметре. Когда-то была необычная идиома в этих строках для работы со старым кодом на C, которому нужны указатели на функции
class myclass
{
public:
virtual void myrealmethod () = 0;
static void myfunction (myclass *p);
}
void myclass::myfunction (myclass *p)
{
p->myrealmethod ();
}
Поскольку myfunction
- действительно просто нормальная функция (проблемы с областью действия), Функциональный указатель можно найти в обычном режиме C.
EDIT - этот метод называется «метод класса» или «статическая функция-член». Основное отличие от функции, не являющейся членом, заключается в том, что если вы ссылаетесь на нее вне класса, вы должны указать область с помощью оператора разрешения области ::
. Например, чтобы получить указатель на функцию, используйте &myclass::myfunction
и вызовите его, используя myclass::myfunction (arg);
.
Подобные вещи довольно распространены при использовании старых API Win32, которые первоначально были предназначены для C, а чем C ++. Конечно, в этом случае параметр обычно является LPARAM или аналогичным, а не указателем, и требуется некоторое литье.