Jakie jest znaczenie const
takich deklaracji? const
Myli mnie.
class foobar
{
public:
operator int () const;
const char* foo() const;
};
Jakie jest znaczenie const
takich deklaracji? const
Myli mnie.
class foobar
{
public:
operator int () const;
const char* foo() const;
};
Odpowiedzi:
Po dodaniu const
słowa kluczowego do metody this
wskaźnik zasadniczo stanie się wskaźnikiem do const
obiektu, a zatem nie można zmienić żadnych danych elementu. (O ile nie użyjesz mutable
, więcej o tym później).
Słowo const
kluczowe jest częścią sygnatury funkcji, co oznacza, że możesz zaimplementować dwie podobne metody, jedną wywoływaną, gdy obiekt jest const
, a drugą nie.
#include <iostream>
class MyClass
{
private:
int counter;
public:
void Foo()
{
std::cout << "Foo" << std::endl;
}
void Foo() const
{
std::cout << "Foo const" << std::endl;
}
};
int main()
{
MyClass cc;
const MyClass& ccc = cc;
cc.Foo();
ccc.Foo();
}
To wyjdzie
Foo
Foo const
W metodzie innej niż const możesz zmienić członków instancji, czego nie można zrobić w const
wersji. Jeśli zmienisz deklarację metody w powyższym przykładzie na poniższy kod, pojawi się kilka błędów.
void Foo()
{
counter++; //this works
std::cout << "Foo" << std::endl;
}
void Foo() const
{
counter++; //this will not compile
std::cout << "Foo const" << std::endl;
}
Nie jest to do końca prawdą, ponieważ można oznaczyć członka jako, mutable
a const
następnie metoda może go zmienić. Najczęściej jest używany do liczników wewnętrznych i innych rzeczy. Rozwiązaniem tego byłby poniższy kod.
#include <iostream>
class MyClass
{
private:
mutable int counter;
public:
MyClass() : counter(0) {}
void Foo()
{
counter++;
std::cout << "Foo" << std::endl;
}
void Foo() const
{
counter++; // This works because counter is `mutable`
std::cout << "Foo const" << std::endl;
}
int GetInvocations() const
{
return counter;
}
};
int main(void)
{
MyClass cc;
const MyClass& ccc = cc;
cc.Foo();
ccc.Foo();
std::cout << "Foo has been invoked " << ccc.GetInvocations() << " times" << std::endl;
}
co by wydało
Foo
Foo const
Foo has been invoked 2 times
Const oznacza, że metoda obiecuje nie zmieniać żadnych członków klasy. Będziesz w stanie wykonać elementy obiektu, które są tak oznaczone, nawet jeśli sam obiekt został oznaczony const
:
const foobar fb;
fb.foo();
byłoby legalne.
Zobacz, ile i jakie są zastosowania „const” w C ++? po więcej informacji.
Te const
środki kwalifikacyjne, że metody można nazwać na dowolnej wartości foobar
. Różnica pojawia się, gdy rozważymy wywołanie metody innej niż const na obiekcie const. Zastanów się, czy Twój foobar
typ ma następującą deklarację metody dodatkowej:
class foobar {
...
const char* bar();
}
Metoda bar()
nie jest stała i można uzyskać do niej dostęp wyłącznie z wartości innych niż stała.
void func1(const foobar& fb1, foobar& fb2) {
const char* v1 = fb1.bar(); // won't compile
const char* v2 = fb2.bar(); // works
}
Ideą const
jest jednak oznaczenie metod, które nie zmienią wewnętrznego stanu klasy. Jest to potężna koncepcja, ale w rzeczywistości nie jest możliwa do wyegzekwowania w C ++. To bardziej obietnica niż gwarancja. I taki, który jest często łamany i łatwo łamany.
foobar& fbNonConst = const_cast<foobar&>(fb1);
const
jest oznaczenie metod, które nie zmienią wewnętrznego stanu klasy”. Właśnie tego szukałem.
const
?
Te const oznaczają, że kompilator wykona błąd, jeśli metoda „with const” zmieni dane wewnętrzne.
class A
{
public:
A():member_()
{
}
int hashGetter() const
{
state_ = 1;
return member_;
}
int goodGetter() const
{
return member_;
}
int getter() const
{
//member_ = 2; // error
return member_;
}
int badGetter()
{
return member_;
}
private:
mutable int state_;
int member_;
};
Test
int main()
{
const A a1;
a1.badGetter(); // doesn't work
a1.goodGetter(); // works
a1.hashGetter(); // works
A a2;
a2.badGetter(); // works
a2.goodGetter(); // works
a2.hashGetter(); // works
}
Przeczytaj to, aby uzyskać więcej informacji
Odpowiedź Blair jest na znaku.
Należy jednak pamiętać, że istnieje element mutable
kwalifikujący, który można dodać do elementów danych klasy. Każdy członek oznaczony w ten sposób może być modyfikowany const
metodą bez naruszaniaconst
umowy.
Możesz użyć tego (na przykład), jeśli chcesz, aby obiekt pamiętał, ile razy jest wywoływana określona metoda, nie wpływając na „logiczną” stałość tej metody.
Znaczenie stałej funkcji członka w C ++ Common Knowledge: Essential Intermediate Programming daje jasne wyjaśnienie:
Typem tego wskaźnika w niestanowionej funkcji składowej klasy X jest X * const. Oznacza to, że jest to stały wskaźnik do niestałego X (patrz Const Wskaźniki i Wskaźniki do Const [7, 21]). Ponieważ obiekt, do którego się to odnosi, nie jest stały, można go modyfikować. Typem tego w stałej funkcji członka klasy X jest const X * const. Oznacza to, że jest to stały wskaźnik do stałej X. Ponieważ obiekt, do którego się to odnosi, jest const, nie można go modyfikować. Na tym polega różnica między stałymi i niepowiązanymi funkcjami składowymi.
W twoim kodzie:
class foobar
{
public:
operator int () const;
const char* foo() const;
};
Możesz myśleć tak:
class foobar
{
public:
operator int (const foobar * const this) const;
const char* foo(const foobar * const this) const;
};
this
nie jest const
. Powodem, dla którego nie można go modyfikować, jest to, że jest to wartość.
kiedy używasz const
w sygnaturze metody (jak powiedziałeś const char* foo() const;
:), mówisz kompilatorowi, że wskazanej przez pamięć pamięci this
nie można zmienić tą metodą (która jest foo
tutaj).
Chciałbym dodać następujący punkt.
Możesz także zrobić to const &
aconst &&
Więc,
struct s{
void val1() const {
// *this is const here. Hence this function cannot modify any member of *this
}
void val2() const & {
// *this is const& here
}
void val3() const && {
// The object calling this function should be const rvalue only.
}
void val4() && {
// The object calling this function should be rvalue reference only.
}
};
int main(){
s a;
a.val1(); //okay
a.val2(); //okay
// a.val3() not okay, a is not rvalue will be okay if called like
std::move(a).val3(); // okay, move makes it a rvalue
}
Popraw odpowiedź. Nie jestem ekspertem
*this
jest zawsze wartością, nawet jeśli funkcja składowa ma kwalifikację-wartości-referencyjnej i jest wywoływana na wartości. Przykład .
Const kluczowe używany z Określa deklaracji funkcji, że jest to funkcja członkiem const i to będzie nie być w stanie zmienić członków danych obiektu.
https://isocpp.org/wiki/faq/const-correctness#const-member-fns
Co to jest „
const
funkcja członka”?Funkcja składowa, która sprawdza (zamiast mutuje) swój obiekt.
Funkcja
const
członka jest oznaczonaconst
sufiksem tuż za listą parametrów funkcji członka. Funkcjeconst
składowe z sufiksem nazywane są „stałymi funkcjami składowymi” lub „inspektorami”. Funkcjeconst
składowe bez sufiksu nazywane są „funkcjami składowymi niepowiązanymi” lub „mutatorami”.class Fred { public: void inspect() const; // This member promises NOT to change *this void mutate(); // This member function might change *this }; void userCode(Fred& changeable, const Fred& unchangeable) { changeable.inspect(); // Okay: doesn't change a changeable object changeable.mutate(); // Okay: changes a changeable object unchangeable.inspect(); // Okay: doesn't change an unchangeable object unchangeable.mutate(); // ERROR: attempt to change unchangeable object }
Próba połączenia
unchangeable.mutate()
jest błędem wychwyconym podczas kompilacji. Nie ma miejsca na czas wykonywania ani ograniczenia prędkościconst
i nie trzeba pisać przypadków testowych, aby sprawdzić to w czasie wykonywania.Funkcja końcowa
const
nainspect()
elemencie członkowskim powinna być używana w celu oznaczenia, że metoda nie zmieni abstrakcyjnego stanu obiektu (widocznego dla klienta). To nieco różni się od stwierdzenia, że metoda nie zmieni „surowych bitów” struktury obiektu. Kompilatory C ++ nie mogą przyjmować interpretacji „bitowej”, chyba że potrafią rozwiązać problem aliasingu, którego normalnie nie można rozwiązać (tzn. Nie istniałby stały alias, który mógłby modyfikować stan obiektu). Kolejny (ważny) wgląd w ten problem aliasingu: wskazywanie na obiekt wskaźnikiem do stałej nie gwarantuje, że obiekt się nie zmieni; po prostu obiecuje, że obiekt nie zmieni się za pomocą tego wskaźnika .