Категориальная конструкция или метод Objective-C в C ++?

Функция категории Objective C позволяет программисту добавлять новый метод, который не был определен в оригинальном определении класса.

Могу ли я заархивировать подобную функциональность (языковую конструкцию или некоторую технику) на C ++?

Основная проблема заключается в согласованном синтаксисе вызова метода (. или же -> оператор).

11

Решение

Давайте рассмотрим следующий класс для расширения:

struct A {
int x, y;
A(int x, int y) : x(x), y(y) {}
};

Вы можете наследовать от этого класса или написать класс-оболочку, который содержит экземпляр этого класса. В большинстве случаев наследование — это путь, как класс-обертка не А, но это обертывания (содержит) А.

С C ++ 11 переместить семантику, продвигая экземпляр A в подкласс B (наследование A) будет эффективным и не требует копирования экземпляра A:

class B : public A {
public:
B (A &&a) : A(a), someOtherMember(a.x + a.y) {}

// added public stuff:
int someOtherFunction() const { return someOtherMember; }

private:
// added private stuff:
int someOtherMember;
};

Полный код с примером: http://ideone.com/mZLLEu

Конечно, функция, которую я добавил, немного глупа (и член еще более, так как он не учитывает дальнейшие изменения первоначальных членов x а также y), но вы должны получить представление о том, что я хочу продемонстрировать.

Обратите внимание на конструктор B (A &&a) это то, что я называю «продвигать конструктор» (это не стандартный термин). Обычно, B (B &&b) это переместить конструктор, который движется содержание предоставленного B экземпляр в новый B собирается быть построенным. Я использую семантику перемещения переехать экземпляр A (который был возвращен другой функцией) в суперкласс A из B,

По сути, вы можете продвигать A в B делая возможным использование B как A,

В отличие от ответа Сунтса, мое решение также работает с добавленными виртуальными таблицами, поскольку оно не основано на небезопасном приведении указателей.

7

Другие решения

Другой вариант, который некоторые могут не рассматривать как «чистый» (хотя это, на мой взгляд), но все же выполняет то же самое, — это использование статического класса. Важно помнить, что когда мы создаем функцию-член, то, что действительно происходит за кулисами, так это то, что компиляция генерирует функцию, в которой объект (он же «this») является первым параметром. Таким образом, мы можем сделать то же самое, чтобы расширить функциональность нашего класса, не используя его.

class Something
{
public:
Something()
~Something()
}

// In objective-c you may call this category Something+Utils
class SomethingUtils
{
// You can use a pointer, or a reference here, your call.
static int GetSomethingElse(Something *something, int parameter);
}

Это достигнет того же намерения, что и категория: вы расширяете функциональные возможности вашего объекта класса, и вам не нужно создавать новый производный класс. Вы не сможете получить доступ к закрытым или защищенным функциям-членам и переменным, но вы все равно не сможете сделать это в target-c, так что на этом фронте ничего не потеряно (и если вы пытаетесь использовать закрытое или защищенное государство-член, вы упустил пункт категории полностью). Вы не сможете использовать. и -> операторы, но, на мой взгляд, это гораздо лучший компромисс, чем вывод нового типа просто для добавления некоторых служебных методов.

5

C ++ имеет наследство для этого. Кроме того, я несколько раз использовал следующий трюк для расширения классов, сгенерированных директивой #import «progid: …»:

// This one is part of external framework, or auto-generated, or dllimport, or #import, etc..
class A
{
protected double m_x;
};

// This one is the extension class. Make sure you only add non-virtual methods here.
// Static methods and static data members are OK as well.
class __declspec( novtable ) B: public A
{
public:
double getSquare(){ return m_x * m_x; }
__declspec( property( get = getSquare ) ) double square;
};

// Usage example
double someFunc( A& arg )
{
B& b = static_cast<B&>( arg ); // Note we've not constructed any instance of B, just casted.
return b.square;
}
1

Я получил около согласованное соглашение о вызовах с идея, о которой я говорил в молниеносной беседе год или около того назад:

(введение не имеет смысла без комментариев — подождите, пока оно не дойдет до бита C ++).

Обратите внимание, что материал не был предназначен для всерьез — хотя некоторые неизбежно имеют 😉

0