How do I return the value of x.value using the pptrx "pointer"?
I think there is already a good explanation above. But I will repeat next.
While doing some pointer tests I came across the following
question: how a pointer to a pointer works when it comes to
classes
About the title itself it is important to understand that the fact that they are pointers to class doesn’t make the slightest difference. It’s just like in C, where it wouldn’t make a difference being pointers to struct
Example
A* pA = nullptr;
A** p2A = nullptr;
A*** p3A = nullptr;
A**** p4A = nullptr;
In that case p3A
is of what type? p3A
is A***
. So
- *p3A is of the type
A**
- **p3A is of the type
A*
- and after all ***p3A is of the type
A
, an instance of class A.
- And that’s what we always have: "take the
*
on one side and place on the other
Since you’re really doing tests and this one I think is a boring piece of C and C++ I’ll leave an example with plus testing. Less and less use is made every day in C++, but it will always be an essential concept for systems development languages when used for, for example, systems development :D
Your class A
slightly altered
class A
{
public:
int value;
A() : A(42){};
A(int v) : value(v){ cout << "Criada A com '" << value << "'\n";};
~A(){ std::cout << "Destruindo instancia de A(" << value << ")\n";};
};
To facilitate the example I added a constructor that accepts a int
for a direct value, and created a destructor to see when the class can be destroyed in the middle of the program, in the case of dynamic allocation.
Test programs are for that after all
I will post some excerpts of the program and the corresponding excerpt in the output, then. At the end I will leave the whole program and the output throughout.
stretch 1
A x; std::cout << x.value << std::endl;
A y(300); std::cout << y.value << std::endl;
A* p1 = nullptr;
This passage creates two A
with values 42 (standard) and 300 and generates
exit
Criada A com '42'
42
Criada A com '300'
300
stretch 2
p1 = &x;
std::cout << p1->value << std::endl;
p1 = new A(322);
std::cout << p1->value << std::endl;
std::cout << "vai destruir p1\n";
delete p1;
std::cout << "continuando...\n";
ago p1
point to x
and displays the value. But then allocate a new p1
pointing to a new A
value 322. Then delete p1
using delete
and then you see the destructor being called.
exit
42
Criada A com '322'
322
vai destruir p1
Destruindo instancia de A(322)
continuando...
Section 3
A** pp1 = new A*(nullptr);
pp1 = &p1;
p1 = &y;
cout << "pp1 aponta para p1 que aponta para y(300). Valor = " << (**pp1).value << "\n";
delete pp1; // libera *pp1;
Now declares pp1
as A**
and makes him point to p1
. p1
not pointing to anything, was targeted delete
np stretch 2. But then the program does p1
point to y, and use **pp1
to print the value of y
which is 300
Exit
pp1 aponta para p1 que aponta para y(300). Valor = 300
stretch 4
*pp1 = &x; // reusa o ponteiro para apontar para o endereco de x
(*pp1)->value = 18; // usa pp1 para alterar o valor de x
cout << "Valor de x alterado para '" << x.value << "'\n";
cout << "pp1 -> p1 -> x(18). Valor = " << (**pp1).value << "\n";
cout << "ou de outro modo Valor = " << (*pp1)->value << "\n";
cout << "ou ainda de outro modo Valor = " << (*(*pp1)).value << "\n";
pp
was targeted by a delete
then pointed to nothing. This section points to pp1
for x
and uses the pointer to change the value of x
to 18 and shows some ways to access
exit
Valor de x alterado para '18'
pp1 -> p1 -> x(18). Valor = 18
ou de outro modo Valor = 18
ou ainda de outro modo Valor = 18
final stretch
// um ultimo exemplo usando pp1 para apontar para x e y
pp1 = (A**)::operator new( 2 *sizeof(A*) );
pp1[0] = &y;
pp1[1] = &x;
cout << "\nx(" << x.value << ")\n";
cout << "y(" << y.value << ")\n";
cout << "Acessando os valores de x e y atraves do vetor\n\
de ponteiros para ponteiros para a classe A:\n\
Valores de y e x: (" <<
pp1[0]->value << "," <<
pp1[1]->value <<
")\n";
delete pp1;
cout << "\nFim\n";
This part has the face of a C program, but uses pp1
that is A**
to create two pointers and access the values of x
and y
. Nothing special, considering that is more or less what happens with every program in C++ to create the list of parameters for int main( int argc, char*[] argv)
.
Pointers are allocated, point to instances x
and y
of A
and are used to display values via cout
. Then the pointers are released and the program ends. Only then x
and y
are destroyed, which is clear at the exit because the message "End" appears before the destructors of x
and y
exit
x(18)
y(300)
Acessando os valores de x e y atraves do vetor
de ponteiros para ponteiros para a classe A:
Valores de y e x: (300,18)
Fim
Destruindo instancia de A(300)
Destruindo instancia de A(18)
The complete program
#include <iostream>
using namespace std;
class A
{
public:
int value;
A() : A(42){};
A(int v) : value(v){ cout << "Criada A com '" << value << "'\n";};
~A(){ std::cout << "Destruindo instancia de A(" << value << ")\n";};
};
int main(void)
{
A x; std::cout << x.value << std::endl;
A y(300); std::cout << y.value << std::endl;
A* p1 = nullptr;
p1 = &x;
std::cout << p1->value << std::endl;
p1 = new A(322);
std::cout << p1->value << std::endl;
std::cout << "vai destruir p1\n";
delete p1;
std::cout << "continuando...\n";
A** pp1 = new A*(nullptr);
pp1 = &p1;
p1 = &y;
cout << "pp1 aponta para p1 que aponta para y(300). Valor = " << (**pp1).value << "\n";
delete pp1; // libera *pp1;
*pp1 = &x; // reusa o ponteiro para apontar para o endereco de x
(*pp1)->value = 18; // usa pp1 para alterar o valor de x
cout << "Valor de x alterado para '" << x.value << "'\n";
cout << "pp1 -> p1 -> x(18). Valor = " << (**pp1).value << "\n";
cout << "ou de outro modo Valor = " << (*pp1)->value << "\n";
cout << "ou ainda de outro modo Valor = " << (*(*pp1)).value << "\n";
// um ultimo exemplo usando pp1 para apontar para x e y
pp1 = (A**)::operator new( 2 *sizeof(A*) );
pp1[0] = &y;
pp1[1] = &x;
cout << "\nx(" << x.value << ")\n";
cout << "y(" << y.value << ")\n";
cout << "Acessando os valores de x e y atraves do vetor\n\
de ponteiros para ponteiros para a classe A:\n\
Valores de y e x: (" <<
pp1[0]->value << "," <<
pp1[1]->value <<
")\n";
delete pp1;
cout << "\nFim\n";
return 0;
}
the complete output
PS C:\src\CPP> g++ -o tst -Wall -std=c++2a tst.cpp
PS C:\src\CPP> ./tst
Criada A com '42'
42
Criada A com '300'
300
42
Criada A com '322'
322
vai destruir p1
Destruindo instancia de A(322)
continuando...
pp1 aponta para p1 que aponta para y(300). Valor = 300
Valor de x alterado para '18'
pp1 -> p1 -> x(18). Valor = 18
ou de outro modo Valor = 18
ou ainda de outro modo Valor = 18
x(18)
y(300)
Acessando os valores de x e y atraves do vetor
de ponteiros para ponteiros para a classe A:
Valores de y e x: (300,18)
Fim
Destruindo instancia de A(300)
Destruindo instancia de A(18)
PS C:\src\CPP>