Menu
Coddy logo textTech

Słowo kluczowe mutable

Część sekcji Programowanie obiektowe ścieżki C++ w Coddy. Lekcja 30 z 104.

Wiesz już, że funkcje składowe const nie mogą modyfikować żadnych zmiennych składowych. Czasami jednak trzeba zmienić składową, która nie wpływa na logiczny stan obiektu — na przykład pamięć podręczną lub licznik dostępu. Słowo kluczowe mutable stanowi wyjątek od ograniczenia const.

Składową mutable można modyfikować nawet wewnątrz funkcji składowej const:

class DataFetcher {
    std::string data;
    mutable int accessCount;    // Może być modyfikowane w funkcjach const
    
public:
    DataFetcher(std::string d) : data(d), accessCount(0) {}
    
    std::string getData() const {
        accessCount++;          // Dozwolone, ponieważ accessCount jest mutable
        return data;
    }
    
    int getAccessCount() const {
        return accessCount;
    }
};

Bez mutable zwiększenie accessCount wewnątrz funkcji const getData() spowodowałoby błąd kompilatora. Słowo kluczowe mutable informuje kompilator: „Ten element może się zmieniać, nawet gdy obiekt jest uznawany za const”.

Typowe zastosowania słowa mutable obejmują buforowanie obliczonych wartości, śledzenie statystyk dostępu oraz prymitywy synchronizacyjne, takie jak muteksy. W każdym przypadku modyfikacja nie zmienia tego, co obiekt reprezentuje logicznie — buforowana wartość jest tylko optymalizacją, a licznik dostępu to metadane dotyczące użycia.

class Circle {
    double radius;
    mutable double cachedArea;
    mutable bool areaCached;
    
public:
    double getArea() const {
        if (!areaCached) {
            cachedArea = 3.14159 * radius * radius;
            areaCached = true;
        }
        return cachedArea;
    }
};

Używaj mutable oszczędnie — należy stosować je tylko do składowych, które nie wpływają na obserwowalny stan obiektu.

challenge icon

Wyzwanie

Łatwy

Stwórzmy przeglądarkę dokumentów, która śledzi, ile razy wyświetlono dokument, nie naruszając poprawności stałości naszych metod tylko do odczytu. To doskonały przykład zastosowania słowa kluczowego mutable.

Utworzysz dwa pliki, aby uporządkować swój kod:

  • Document.h: Zdefiniuj klasę Document, która przechowuje treść i dyskretnie śledzi statystyki wyświetleń. Twoja klasa powinna zawierać:
    • Pola prywatne: title (string), content (string) oraz mutable int viewCount, które można modyfikować nawet w metodach const
    • Konstruktor, który przyjmuje tytuł i treść, inicjalizując viewCount wartością 0
    • Metodę getTitle() const, która zwraca tytuł
    • Metodę getContent() const, która zwiększa viewCount (jest to dozwolone, ponieważ pole jest mutable) i zwraca treść
    • Metodę getViewCount() const, która zwraca liczbę dostępów do treści
    • Metodę getPreview() const, która zwraca pierwsze 20 znaków treści, po których następuje "...". Nie powinna ona zwiększać licznika wyświetleń, ponieważ jest to tylko podgląd
  • main.cpp: Pokaż, jak mutable pozwala śledzić statystyki dostępu przy zachowaniu logicznej stałości metod. Wczytaj tytuł i treść dokumentu z wejścia (każde w osobnym wierszu), a następnie:
    • Utwórz obiekt Document z wczytanymi wartościami
    • Wypisz "Title: <title>"
    • Wypisz "Preview: <preview>"
    • Wypisz "Views after preview: <count>"
    • Pobierz całą treść za pomocą getContent() i wypisz "Content: <content>"
    • Wypisz "Views after first read: <count>"
    • Pobierz treść ponownie i wypisz "Content: <content>"
    • Wypisz "Views after second read: <count>"
    • Utwórz funkcję pomocniczą void displayDocument(const Document& doc), która wypisuje "[Const Access] <title>: <content>". Dowodzi to, że nasze metody const działają z referencjami const
    • Wywołaj displayDocument(), przekazując jej swój dokument
    • Wypisz "Final view count: <count>"

Licznik wyświetleń powinien wynosić 0 po wyświetleniu podglądu (ponieważ podglądy nie są liczone jako pełne wyświetlenia), a następnie zwiększać się za każdym razem, gdy wywołana zostanie metoda getContent(). Słowo kluczowe mutable to umożliwia — bez niego nie można byłoby modyfikować viewCount wewnątrz metod const, takich jak getContent().

Jeśli treść ma mniej niż 20 znaków, metoda getPreview() powinna zwrócić całą treść, po której następuje "...".

Spróbuj swoich sił

#include <iostream>
#include <string>
#include "Document.h"
using namespace std;

// TODO: Zaimplementuj funkcję displayDocument
// Powinna wypisać: "[Const Access] <title>: <content>"
void displayDocument(const Document& doc) {
    // TODO: Zaimplementuj tę funkcję
}

int main() {
    // Wczytaj dane wejściowe
    string title;
    string content;
    getline(cin, title);
    getline(cin, content);
    
    // TODO: Utwórz Document z wartościami wejściowymi
    
    // TODO: Wypisz "Title: <title>"
    
    // TODO: Wypisz "Preview: <preview>"
    
    // TODO: Wypisz "Views after preview: <count>"
    
    // TODO: Uzyskaj dostęp do pełnej zawartości i wypisz "Content: <content>"
    
    // TODO: Wypisz "Views after first read: <count>"
    
    // TODO: Ponownie uzyskaj dostęp do zawartości i wypisz "Content: <content>"
    
    // TODO: Wypisz "Views after second read: <count>"
    
    // TODO: Wywołaj displayDocument() ze swoim dokumentem
    
    // TODO: Wypisz "Final view count: <count>"
    
    return 0;
}
quiz iconSprawdź się

Ta lekcja zawiera krótki quiz. Zacznij lekcję, żeby na niego odpowiedzieć i śledzić swoje postępy.

Wszystkie lekcje w sekcji Programowanie obiektowe

Poćwicz samodzielnie: Kompilator C++ online