C ++ кеңейтім функциялары?

C ++ сияқты кеңейтімдер бар ма C #?

Мысалы, C# -де сіз:

public static uint SwapEndian(this uint value)
{
    var tmp = BitConverter.GetBytes(value);
    Array.Reverse(tmp);
    return BitConverter.ToUInt32(tmp, 0);
}

someuint.SwapEndian();

C ++-те осындай нәрсе бар ма?

13
Жоқ, C ++ сияқты ештеңе жоқ. AFAIK, бұл туралы C ++ 17 туралы ешқандай ұсыныстар жоқ (жазыңыз!). D бағдарламалау тілінде UFCS (бірыңғай функционалдық шақыру синтаксисі) бар, ол дәл «кеңейтетін әдістер» болып табылады. Бұл мүше емес басқа да функцияларды жазуға және объект параметрінен аулақ болуға мүмкіндік беретіндіктен, «солға-оңға» оқуға болатын кодты шығаруға болатындықтан, «out-of-out/right-to- сол».
қосылды автор gnzlbg, көзі
Бұл C ++-нің жарамды бағдарламалау тілі деп саналмайтын себептерінің бірі. Бұл тым ескірген, C# сияқты заманауи тілдердің көптеген ерекшеліктері жоқ және өнімділікке қарама-қайшы. Microsoft корпорациясы C #/Java сияқты жаңа құрастырылған тілмен қайтадан іске қосылуы керек. Егер біреу маған C ++-ды қолданатындығын айтса, мен оларға күліп, оларды өзімнен әлдеқайда ақылды деп көремін.
қосылды автор Krythic, көзі

7 жауаптар

C ++-де кеңейтім функциялары жоқ. Оларды еркін функциялар ретінде ғана анықтауға болады.

uint SwapEndian(uint value){ ... }
5
қосылды
Бұл бастапқы кодты пайдаланатын жалғыз жауап; Рақмет сізге. Сондай-ақ, бұл бос функциялар дегеннің мағынасын көрсетіп, басқа да жауаптардың көпшілігінде және басқа жерде жоқ. Осыған байланысты басқа да жауаптардағы кейбір жауаптар OOP-ның ұзақ философиялық сипаттамасын және оның қалай жұмыс істейтінін, бірақ пайдалы мәліметтердің жоқтығын береді.
қосылды автор user34660, көзі

Кеңейтім әдістері (сонымен қатар «статикалық сыныптар») C #/Java тілдерінде ғана бар, себебі дизайнерлер OOP-ның Java әдісі - One True Way және барлық сыныптың әдісі болуы керек деп шешкендіктен:

Бұл әрекеттер C ++ емес. C ++ жүйесінде аттар кеңістігі, тегін функциялар және сыныптың мінез-құлқын кеңейту үшін Koenig іздеу бар:

namespace foo
{
    struct bar { ... };

    void act_on_bar(const bar& b) { ... };
}

...

foo::bar b;
act_on_bar(b);//No need to qualify because of Koenig lookup

Мен әдетте зиянды әдістерді қарастырамын. Егер сіз сыныпқа тым көп мінез-құлық танытсаңыз, онда сіз сыныптың бар болу себебін басып шығара алмайсыз. Сондай-ақ («жартылай сыныптар» сияқты) олар жергілікті емес классқа қатысты кодты жасайды. Бұл жаман.

Сіздің мәселеңізге байланысты C ++ -де сіз:

template 
T swap_endian(T x)
{
    union { T value; char bytes[sizeof(T)]; } u;
    u.value = x;

    for (size_t i = 0; i < sizeof(T)/2; i++) 
        swap(u.bytes[i], u.bytes[sizeof(T) - i - 1]);

    return u.value;
}

Қолданылуы:

swap_endian(42);

немесе егер түрін шығаруға болады:

std::uint64_t x = 42;
std::uint64_t y = swap_endian(x);
5
қосылды
@gnzlbg, келісілді. Кейде олар C# -де ыңғайлы болды, бірақ C# стилін кеңейту әдісі әрқашан this дегенді const емес T & (сілтеме) ретінде алды. b (a) ab() -ге тең болатын жағдайда, b бірінші аргументі көрсеткіш немесе сілтеме болу керек ? Көшіріп алудың мағынасы бар ма? Мен бұл синтаксисті C ++ бағдарламасында қолжетімді болғым келеді және оны қоғамға және комитет тарапынан немқұрайдылықпен бөлісетін басқа кедергілер бар ма?
қосылды автор Drew Noakes, көзі
Кеңейтім әдісі - бұл жай ғана синтаксистік қант .. Сізде act_on_bar тегін функциясы болуы мүмкін және оны act_on_bar (b) немесе b.act_on_bar() . Екінші жолы ештеңе шынымен OO жолымен , тек оқуға арналған. Мысалы: егер сізде 2 функция болса; act2 (act1 (b)) b.act1() функциясынан аз оқиды. act2() . C ++-де сізге міндетті act1 және act2 мүшесінің функцияларын, оқуға болатын кодты алу үшін, ! Бұл сондай-ақ жалпы бағдарламаларды жақсартады. Және оқу мүмкіндігі субъективтік емес, өйткені көптеген адамдар мәтінді оңнан солға қарай оқып, сыртқа шықпайды.
қосылды автор gnzlbg, көзі
Бірақ, сөзсіз, бұл қағида мүлдем сабақсыз қолданылуы мүмкін. C классы үшін функцияларды кластарға тән мәңгілік құрылымға мәжбүрлеместен сабаққа байланыстырады. Мен құрылымдарды немесе примитивтерді функцияларды байланыстыратын немесе бақыланбайтын бүркітсіз байланыстыра аламын (өйткені, мен өзімді байланыстырамын, компиляция уақытында аударылғандықтан, ештеңе жоқ). Нәтижелі бинарға нөлдік абстракциядан босатылған абстракциялар әдемі.
қосылды автор Dmitry, көзі

Осылай емес, бірақ сіз мүмкін сіз жазған сыныптарда жұмыс жасайтын оператор жүктемелерін жазады және бұл әдіс кеңейтіліміне ұқсас (бірақ аталған функциялар үшін емес, операторлар үшін ғана емес) бұл сынып қазірдің өзінде анықталған). Классикалық мысал сіздің сынып жұмысын cout :

class MyClass {
public:
    MyClass(const char* blah) : str(blah) { }

    const char* string() const {
        return str;
    }

private:
    const char* str;
};

// this is kinda like a method extension
ostream& operator<<(ostream& lhs, const MyClass& rhs) {
    lhs << rhs.string();
}

// then you can use it like this
MyClass m("hey ho");
cout << m;

// prints hey ho

Бұл, әрине, тривиальды үлгі, бірақ сіз идеяны аласыз.

3
қосылды

Тікелей ұқсас емес, бірақ бірнеше рет шаблондарды қолдану арқылы қалаған нәтижеге қол жеткізуге болады. Сіз C ++-де нақты сыныпқа түпнұсқа классынан шықпай-ақ «қосасыз» әдістерін енгізе алмайсыз, бірақ кез келген түрдегі жұмыс үлгісін жасауға болады.

Мысалы, кез-келген интегралды түрдегі ntoh түріндегі түрлендірулерді орындау үшін пайдаланатын функция үлгісі кітапханасы:

template inline Val ntohx(const Val& in)
{
    char out[sizeof(in)] = {0};
    for( size_t i = 0; i < sizeof(Val); ++i )
        out[i] = ((char*)&in)[sizeof(Val)-i-1];
    return *(reinterpret_cast(out));
}

template<> inline unsigned char ntohx(const unsigned char & v )
{
    return v;
}
template<> inline uint16_t ntohx(const uint16_t & v)
{
    return ntohs(v);
}

template<> inline uint32_t ntohx(const uint32_t & v)
{
    return ntohl(v);
}

template<> inline uint64_t ntohx(const uint64_t & v)
{
    uint32_t ret [] =
    {
        ntohl(((const uint32_t*)&v)[1]),
        ntohl(((const uint32_t*)&v)[0])
    };
    return *((uint64_t*)&ret[0]);
}
template<> inline float ntohx(const float& v)
{
    uint32_t const* cast = reinterpret_cast(&v);
    uint32_t ret = ntohx(*cast);
    return *(reinterpret_cast(&ret));
};
2
қосылды
@Alexandre: Бұл сіздікі сияқты. Жалғыз айырмашылық мынада, мен ntohs және ntohl арқылы өңделе алатын кіріктірілген түрлерге арналған мамандандырулар бердім.
қосылды автор John Dibling, көзі
Бұл тапсырманы орындаудың өте күрделі тәсілі.
қосылды автор Alexandre C., көзі
in ntohx қайтаратын массивтің екі 32-биттік мәндері дұрыс тәртіпте қалай екенін білесіз бе? ;)
қосылды автор Géza Török, көзі

Жоқ, кешіріңіз, бірақ C ++-де мұндай ештеңе жоқ және ол ешқашан болмайды. Стандарттың іске асырылуына тәуелді болып кететін көптеген нәрселер бар (яғни, компилятор оны кез келген тәсілмен көре алады), сондай-ақ C ++ стандартталмаған ABI .

1
қосылды
@Sean: Кеңейтім әдістері осы сценарийді қолдауы керек: сіз А-да анықталған түрлерде кеңейтілген әдістерді анықтайтын және қолданатын кейбір үшінші тарап кітапханасының А және сіздің жеке кодыңыз (B кітапханасы) қабылдайсыз. A әртүрлі компиляторлар/байланыстырғыштармен өте жақсы жасалуы мүмкін ықтимал алдын-ала орнатылған бинарға қоңырауларды қалай қосу керектігін үйреніңіз. ABI-те стандарттау болмаса, (бұлар БК үзілістеріне байланысты ашық айтылмайды) сіз мұны ешқашан жасай алмайсыз.
қосылды автор Jon, көзі
@Sean: Басқа әдісті енгізу үшін: .NET ішіне жинақтарда олар қамтылған түрлерге өте егжей-тегжейлі метадеректер болуы керек. C ++ OTOH-де сіз өзіңіздің атыңыз бен басқа мәліметтерді ешқашан ескермеген кейбір сыныпты қамтитын ipucu екілік қатарында ештеңе жоқ екеніне ешқандай кепілдік жоқ.
қосылды автор Jon, көзі
Менің ойымша, «ол ешқашан да мүмкін емес» деп ойлаймын, бұл біраз ақталмайды. Олар кеңейтілім әдісінің қандай да бір үлгісін қосып, олар қалаған болса ғана, олар таңдаған жоқ.
қосылды автор Sean, көзі

One method I have found is to use the overloaded ">>" operator with lambda expressions. The following code demonstrates this. You have to know to use operator ">>" instead of "->", this is because the compiler I use will not allow the operator "->" to be overloaded. Also because the operator ">>" has lower precedence than the "->" you have to use parentheses to force to compiler to evaluate the equation in the correct order.

Ақыр соңында, ол сіз жасайтын тырысып жатқан стилдің стилі, күтуге қабілеттілігі, сенімділігі мен тазалығына айналады. «SubtractValue» әдісін анықтау екі дәлелмен тиімді кодын жасайды, бірақ басқалары шамадан тыс жүктелген әдіс әлдеқайда оңтайлы екендігіне күмән келтіреді. Нәтижесінде сәулетшілер мен әзірлеушілер өз жобалары үшін маңызды екенін анықтауға қалды. Мен мәселені шешуге мүмкіндік беремін.

#include 
#include 
#include 
#include 

// Some plain demo class that cannot be changed.
class DemoClass
{
public:
    int GetValue() { return _value; }
    int SetValue(int ivalue) { _value = ivalue; return _value; }
    DemoClass *AddValue(int iadd) { this->_value += iadd; return this; }

private:
    int _value = 0;
};

// Define Lambda expression type that takes and returns a reference to the object.
typedef std::function DemoClassExtension;

// Overload the ">>" operator because we cannot overload "->" to execute the extension.
DemoClass* operator>>(DemoClass *pobj, DemoClassExtension &method)
{
    return method(pobj);
}

// Typical extensions.

// Subtract value "isub".
DemoClassExtension SubtractValue(int isub)
{
    return [=](DemoClass *pobj) {
        pobj->AddValue(-isub);
        return pobj;
    };
}

// Multiply value "imult".
DemoClassExtension MultiplyValue(int imult)
{
    return [=](DemoClass *pobj) {
        pobj->SetValue(pobj->GetValue() * imult);
        return pobj;
    };
}

int _tmain(int argc, _TCHAR* argv[])
{
    DemoClass *pDemoObject = new DemoClass();
    int value = (pDemoObject->AddValue(14) >> SubtractValue(4) >> MultiplyValue(2))->GetValue();
    std::cout << "Value is " << value;
    return 0;
}

Жоғарыда келтірілген кодтың шығу мәні «Мағына 20».

1
қосылды

this -qualified method параметріне сілтеме жасасаңыз, онда жоқ. Бірақ сіздің арнайы пайдалану жағдайларыңызға байланысты басқа да ақылдылықтың болуы мүмкін ... Толығырақ ақпаратты бере аласыз ба?

1
қосылды