Zoeken…


Opmerkingen

De this aanwijzer is een sleutelwoord voor C ++ en daarom is er geen bibliotheek nodig om dit te implementeren. En vergeet niet dat this een wijzer is! Dus je kunt niet doen:

 this.someMember();

Wanneer u lidfuncties of lidvariabelen opent vanuit aanwijzers met het pijlsymbool -> :

this->someMember();

Andere nuttige links naar een beter begrip van this aanwijzer:

Wat is de 'deze' wijzer?

http://www.geeksforgeeks.org/this-pointer-in-c/

https://www.tutorialspoint.com/cplusplus/cpp_this_pointer.htm

deze aanwijzer

Alle niet-statische lidfuncties hebben een verborgen parameter, een verwijzing naar een instantie van de klasse, this genaamd; deze parameter wordt stil toegevoegd aan het begin van de parameterlijst en wordt volledig afgehandeld door de compiler. Wanneer een lid van de klas binnen een ledenfunctie wordt benaderd, wordt het stilzwijgend bereikt via this ; Hierdoor kan de compiler een enkele niet-statische lidfunctie gebruiken voor alle instanties en kan een lidfunctie andere lidfuncties polymorf aanroepen.

struct ThisPointer {
    int i;

    ThisPointer(int ii);

    virtual void func();

    int  get_i() const;
    void set_i(int ii);
};
ThisPointer::ThisPointer(int ii) : i(ii) {}
// Compiler rewrites as:
ThisPointer::ThisPointer(int ii) : this->i(ii) {}
// Constructor is responsible for turning allocated memory into 'this'.
// As the constructor is responsible for creating the object, 'this' will not be "fully"
// valid until the instance is fully constructed.

/* virtual */ void ThisPointer::func() {
    if (some_external_condition) {
        set_i(182);
    } else {
        i = 218;
    }
}
// Compiler rewrites as:
/* virtual */ void ThisPointer::func(ThisPointer* this) {
    if (some_external_condition) {
        this->set_i(182);
    } else {
        this->i = 218;
    }
}

int  ThisPointer::get_i() const { return i; }
// Compiler rewrites as:
int  ThisPointer::get_i(const ThisPointer* this) { return this->i; }

void ThisPointer::set_i(int ii) { i = ii; }
// Compiler rewrites as:
void ThisPointer::set_i(ThisPointer* this, int ii) { this->i = ii; }

In een constructor kan this veilig worden gebruikt om (impliciet of expliciet) toegang te krijgen tot elk veld dat al is geïnitialiseerd, of elk veld in een bovenliggende klasse; omgekeerd is (impliciet of expliciet) toegang tot velden die nog niet zijn geïnitialiseerd, of velden in een afgeleide klasse, onveilig (omdat de afgeleide klasse nog niet is geconstrueerd, en dus zijn velden niet geïnitialiseerd of bestaand). Het is ook onveilig om via this functie virtuele lidfuncties in de constructor aan te roepen, omdat afgeleide klassefuncties niet in aanmerking worden genomen (vanwege de afgeleide klasse die nog niet is geconstrueerd en dus de constructor de vtable nog niet bijwerkt).


Merk ook op dat terwijl in een constructor, het type van het object het type is dat die constructor construeert. Dit geldt zelfs als het object als een afgeleid type wordt gedeclareerd. In het onderstaande voorbeeld zijn bijvoorbeeld ctd_good en ctd_bad type CtorThisBase in CtorThisBase() en type CtorThis in CtorThis() , ook al is hun canonieke type CtorThisDerived . Omdat de meer afgeleide klassen zijn opgebouwd rond de basisklasse, gaat de instantie geleidelijk door de klassenhiërarchie totdat deze een volledig geconstrueerde instantie van het beoogde type is.

class CtorThisBase {
    short s;

  public:
    CtorThisBase() : s(516) {}
};

class CtorThis : public CtorThisBase {
    int i, j, k;

  public:
    // Good constructor.
    CtorThis() : i(s + 42), j(this->i), k(j) {}

    // Bad constructor.
    CtorThis(int ii) : i(ii), j(this->k), k(b ? 51 : -51) {
        virt_func();
    }

    virtual void virt_func() { i += 2; }
};

class CtorThisDerived : public CtorThis {
    bool b;

  public:
    CtorThisDerived()       : b(true) {}
    CtorThisDerived(int ii) : CtorThis(ii), b(false) {}

    void virt_func() override { k += (2 * i); }
};

// ...

CtorThisDerived ctd_good;
CtorThisDerived ctd_bad(3);

Met deze klassen en ledenfuncties:

  • In de goede constructor, voor ctd_good :
    • CtorThisBase is volledig gebouwd tegen de tijd dat de CtorThis constructor wordt ingevoerd. Daarom bevindt s zich tijdens het initialiseren van i in een geldige status en is dus toegankelijk.
    • i wordt geïnitialiseerd voordat j(this->i) wordt bereikt. Daarom bevindt i zich in een geldige status tijdens het initialiseren van j en is dus toegankelijk.
    • j wordt geïnitialiseerd voordat k(j) wordt bereikt. Daarom bevindt j zich in een geldige status tijdens het initialiseren van k en is dus toegankelijk.
  • In de slechte constructor, voor ctd_bad :
    • k wordt geïnitialiseerd nadat j(this->k) is bereikt. Daarom bevindt k zich in een ongeldige status tijdens het initialiseren van j en veroorzaakt toegang tot ongedefinieerd gedrag.
    • CtorThisDerived wordt pas gebouwd nadat CtorThis is gebouwd. Daarom bevindt b zich in een ongeldige status tijdens het initialiseren van k en veroorzaakt toegang tot ongedefinieerd gedrag.
    • Het object ctd_bad is nog steeds een CtorThis totdat het CtorThis() verlaat en zal niet worden bijgewerkt om de CtorThisDerived van CtorThisDerived te gebruiken tot CtorThisDerived() . Daarom zal virt_func() CtorThis::virt_func() , ongeacht of het de bedoeling is dat aan te roepen of CtorThisDerived::virt_func() .

Gebruik deze aanwijzer om toegang te krijgen tot lidgegevens

In deze context is het gebruik van this aanwijzer niet helemaal noodzakelijk, maar het zal uw code duidelijker maken voor de lezer, door aan te geven dat een bepaalde functie of variabele lid is van de klasse. Een voorbeeld in deze situatie:

// Example for this pointer
#include <iostream>
#include <string>

using std::cout;
using std::endl;

class Class
{
  public:
    Class();
    ~Class();
    int getPrivateNumber () const;
  private:
    int private_number = 42;
};

Class::Class(){}
Class::~Class(){}

int Class::getPrivateNumber() const
{
    return this->private_number;
}

int main()
{
    Class class_example;
    cout << class_example.getPrivateNumber() << endl;
}

Zie het in actie hier .

Gebruik deze aanwijzer om onderscheid te maken tussen lidgegevens en parameters

Dit is een echte nuttige strategie om lidgegevens te onderscheiden van parameters ... Laten we dit voorbeeld nemen:

// Dog Class Example
#include <iostream>
#include <string>

using std::cout;
using std::endl;

/*
* @class Dog
*   @member name
*       Dog's name
*   @function bark
*       Dog Barks!
*   @function getName
*       To Get Private
*       Name Variable
*/
class Dog
{
 public:
    Dog(std::string name);
    ~Dog();
    void  bark() const;
    std::string  getName() const;
 private:
    std::string name;
};

Dog::Dog(std::string name)
{
    /*
    *  this->name is the
    *  name variable from 
    *  the class dog . and
    *  name is from the 
    *  parameter of the function
    */
    this->name = name; 
}

Dog::~Dog(){}

void Dog::bark() const
{
  cout << "BARK" << endl;   
}

std::string  Dog::getName() const
{
    return this->name;
}


int main()
{
    Dog dog("Max");
    cout << dog.getName() << endl;
    dog.bark();
}

U kunt hier in de constructor zien dat we het volgende uitvoeren:

this->name = name; 

Hier kunt u zien dat we de parameternaam vergelijken met de naam van de privévariabele uit de klasse Dog (deze-> naam).

Om de uitvoer van bovenstaande code te zien: http://cpp.sh/75r7

deze Pointer CV-kwalificaties

this kan ook cv-gekwalificeerd zijn, hetzelfde als elke andere aanwijzer. Omdat this parameter niet in de parameterlijst wordt vermeld, is hiervoor een speciale syntaxis vereist; de cv-kwalificaties worden vermeld na de parameterlijst, maar vóór het hoofdgedeelte van de functie.

struct ThisCVQ {
    void no_qualifier()                {} // "this" is: ThisCVQ*
    void  c_qualifier() const          {} // "this" is: const ThisCVQ*
    void  v_qualifier() volatile       {} // "this" is: volatile ThisCVQ*
    void cv_qualifier() const volatile {} // "this" is: const volatile ThisCVQ*
};

Omdat this een parameter is, kan een functie worden overbelast op basis van this cv-kwalificatie (s) .

struct CVOverload {
    int func()                { return    3; }
    int func() const          { return   33; }
    int func() volatile       { return  333; }
    int func() const volatile { return 3333; }
};

Als this const (inclusief const volatile ), kan de functie er niet impliciet of expliciet naar lidvariabelen naar schrijven. De enige uitzondering hierop zijn mutable lidvariabelen , die kunnen worden geschreven ongeacht het feit. Hierdoor wordt const gebruikt om aan te geven dat de lidfunctie de logische status van het object (de manier waarop het object naar de buitenwereld verschijnt) niet verandert, zelfs als het de fysieke status wijzigt (de manier waarop het object onder de motorkap kijkt) ).

Logische status is de manier waarop het object wordt weergegeven aan externe waarnemers. Het is niet direct gekoppeld aan fysieke toestand en kan zelfs niet eens als fysieke toestand worden opgeslagen. Zolang waarnemers van buitenaf geen wijzigingen kunnen zien, is de logische status constant, zelfs als u alle bits in het object omdraait.

Fysieke toestand, ook bekend als bitgewijze toestand, is hoe het object in het geheugen wordt opgeslagen. Dit is de nitty-gritty van het object, de ruwe enen en nullen waaruit de gegevens bestaan. Een object is alleen fysiek constant als de weergave ervan in het geheugen nooit verandert.

Merk op dat C ++ const baseert op logische toestand, niet op fysieke toestand.

class DoSomethingComplexAndOrExpensive {
    mutable ResultType cached_result;
    mutable bool state_changed;

    ResultType calculate_result();
    void modify_somehow(const Param& p);

    // ...

  public:
    DoSomethingComplexAndOrExpensive(Param p) : state_changed(true) {
        modify_somehow(p);
    }

    void change_state(Param p) {
        modify_somehow(p);
        state_changed = true;
    }

    // Return some complex and/or expensive-to-calculate result.
    // As this has no reason to modify logical state, it is marked as "const".
    ResultType get_result() const;
};
ResultType DoSomethingComplexAndOrExpensive::get_result() const {
    // cached_result and state_changed can be modified, even with a const "this" pointer.
    // Even though the function doesn't modify logical state, it does modify physical state
    //  by caching the result, so it doesn't need to be recalculated every time the function
    //  is called.  This is indicated by cached_result and state_changed being mutable.

    if (state_changed) {
        cached_result = calculate_result();
        state_changed = false;
    }

    return cached_result;
}

Merk op dat terwijl je technisch zou kunnen gebruiken const_cast op this om het non-cv-gekwalificeerd te maken, je echt, echt niet, en moet gebruiken mutable in plaats daarvan. Een const_cast dreigt te roepen onbepaald gedrag bij gebruik op een object dat eigenlijk const , terwijl mutable is bedoeld veilig te gebruiken zijn. Het is echter mogelijk dat u dit tegenkomt in extreem oude code.

Een uitzondering op deze regel is het definiëren van niet-cv-gekwalificeerde accessors in termen van const accessors; omdat het object gegarandeerd geen const als de niet-cv-gekwalificeerde versie wordt aangeroepen, is er geen risico op UB.

class CVAccessor {
    int arr[5];

  public:
    const int& get_arr_element(size_t i) const { return arr[i]; }

    int& get_arr_element(size_t i) {
        return const_cast<int&>(const_cast<const CVAccessor*>(this)->get_arr_element(i));
    }
};

Dit voorkomt onnodige duplicatie van code.


Net als bij reguliere pointers, wordt this , als this volatile (inclusief const volatile ), elke keer dat het wordt gebruikt uit het geheugen geladen, in plaats van in de cache te worden opgeslagen. Dit heeft dezelfde effecten op de optimalisatie als een andere aanwijzer volatile zou verklaren, dus wees voorzichtig.


Merk op dat als een instantie cv-gekwalificeerd is, de enige lidfuncties waartoe het toegang heeft, lidfuncties zijn waarvan this aanwijzer minstens even cv-gekwalificeerd is als de instantie zelf:

  • Niet-cv-instanties hebben toegang tot alle lidfuncties.
  • const instanties hebben toegang tot const en const volatile functies.
  • volatile instanties hebben toegang tot volatile en const volatile functies.
  • const volatile instanties hebben toegang tot const volatile functies.

Dit is een van de belangrijkste principes van const correctheid .

struct CVAccess {
    void    func()                {}
    void  func_c() const          {}
    void  func_v() volatile       {}
    void func_cv() const volatile {}
};

CVAccess cva;
cva.func();    // Good.
cva.func_c();  // Good.
cva.func_v();  // Good.
cva.func_cv(); // Good.

const CVAccess c_cva;
c_cva.func();    // Error.
c_cva.func_c();  // Good.
c_cva.func_v();  // Error.
c_cva.func_cv(); // Good.

volatile CVAccess v_cva;
v_cva.func();    // Error.
v_cva.func_c();  // Error.
v_cva.func_v();  // Good.
v_cva.func_cv(); // Good.

const volatile CVAccess cv_cva;
cv_cva.func();    // Error.
cv_cva.func_c();  // Error.
cv_cva.func_v();  // Error.
cv_cva.func_cv(); // Good.

deze Pointer Ref-kwalificaties

C ++ 11

Net als bij this cv-kwalificaties kunnen we hier ook *this ref-kwalificaties op toepassen. Ref-kwalificaties worden gebruikt om te kiezen tussen normale en rvalue-referentiesemantiek, waardoor de compiler semantiek kan kopiëren of verplaatsen, afhankelijk van welke meer geschikt zijn, en op *this plaats this worden toegepast.

Merk op dat ondanks ref-kwalificaties die syntaxis van referenties gebruiken, this zelf nog steeds een pointer is. Merk ook op dat ref-qualifiers het type *this niet veranderen; het is gewoon gemakkelijker om hun effecten te beschrijven en te begrijpen door ernaar te kijken alsof ze dat deden.

struct RefQualifiers {
    std::string s;

    RefQualifiers(const std::string& ss = "The nameless one.") : s(ss) {}

    // Normal version.
    void func() &  { std::cout << "Accessed on normal instance "    << s << std::endl; }
    // Rvalue version.
    void func() && { std::cout << "Accessed on temporary instance " << s << std::endl; }

    const std::string& still_a_pointer() &  { return this->s; }
    const std::string& still_a_pointer() && { this->s = "Bob"; return this->s; }
};

// ...

RefQualifiers rf("Fred");
rf.func();              // Output:  Accessed on normal instance Fred
RefQualifiers{}.func(); // Output:  Accessed on temporary instance The nameless one

Een ledenfunctie kan geen overbelasting hebben, zowel met als zonder ref-kwalificaties; de programmeur moet kiezen tussen het een of het ander. Gelukkig kunnen cv-qualifiers worden gebruikt in combinatie met ref-qualifiers, waardoor const correctheidsregels kunnen worden gevolgd.

struct RefCV {
    void func() &                {}
    void func() &&               {}
    void func() const&           {}
    void func() const&&          {}
    void func() volatile&        {}
    void func() volatile&&       {}
    void func() const volatile&  {}
    void func() const volatile&& {}
};


Modified text is an extract of the original Stack Overflow Documentation
Licentie onder CC BY-SA 3.0
Niet aangesloten bij Stack Overflow