Como criar array estilo C ou vector de objetos diferentes em C++?

1. Como criar array estilo C ou vector de objetos diferentes em C++?

Perfil removido
removido

(usa Nenhuma)

Enviado em 08/01/2018 - 14:40h

Gostaria de saber como faço para criar um array estilo C ou um vector de **objetos diferentes** em C++?


  


2. Re: Como criar array estilo C ou vector de objetos diferentes em C++?

Hugo Fernandes
Hgfs

(usa Arch Linux)

Enviado em 08/01/2018 - 16:32h

Eu faria uma classe base e derivaria dela as classes que eu quero guardar nesse vector.
Dessa forma, bastaria instanciar um vector da classe base.



3. Re: Como criar array estilo C ou vector de objetos diferentes em C++?

Paulo
paulo1205

(usa Ubuntu)

Enviado em 08/01/2018 - 17:24h

Na verdade, não seria um vetor de elementos da classe base, mas um vetor (ou array) de elementos ponteiros para a classe base, de modo a que um eventual polimorfismo pudesse funcionar.

Alternativamente, se não se quiser ter uma base comum, pode-se trabalhar com std::vector<void *> nome_do_vetor ou void *nome_do_aray[tamanho].

Em qualquer caso, para obter o dado apontado, você teria de ter polimorfismo ou de converter o ponteiro genérico para um ponteiro para o tipo correto de dado antes de o derreferenciar.

void *array_generico[10];
std::vector<void *> vetor_generico;

vetor_generico.push_back(const_cast<char *>("Paulo")); // Aponta para uma constante do programa (depois de desconsiderar o atributo constante).
vetor_generico.push_back(new int(1205)); // Aloca novo inteiro e lhe atribui o valor 1205.
vetor_generico.push_back(array_generico); // Pega o endereço do array (que coincide numericamente com o endereço do primeiro elemento).

for(int n=0; n<std::min(10, vetor_generico.size()); n++){
array_generico[n]=vetor_generico[n]; // ATENÇÃO: Os elementos do vetor e do array apontam para os mesmos dados!
}

std::cout << *static_cast<char *>(vetor_generico[0]) << '\n'; // OK: o tipo do elemento realmente é um array de caracteres que aponta para uma string.
std::cout << *array_generico[1] << '\n'; // ERRO: não posso derreferenciar um ponteiro para void.
std::cout << *static_cast<int *>(vetor_generico[2]) << '\n'; // ALERTA: Funciona, mas pode não fazer sentido, especialmente se sizeof(void *)<sizeof(int).


No código acima, cabe a você lembrar o tipo de cada elemento, bem como se ele deve ou não ser desalocado no momento em que o array ou vetor não for mais necessário.

Você pode ainda tentar variações baseadas em smart pointers, como std::vector<std::unique_ptr<void>> ou std::vector<std::shared_ptr<classe_base>>.


4. Re: Como criar array estilo C ou vector de objetos diferentes em C++?

Fernando
phoemur

(usa Debian)

Enviado em 08/01/2018 - 19:06h

À partir do C++17 você pode também usar o std::any , que basicamente é um cointainer para qualquer tipo de valor.
http://en.cppreference.com/w/cpp/utility/any

Assim, você pode criar um vector<any> e colocar qualquer coisa dentro dele que dá certo:
Se você não tiver acesso ao C++17, é quase a mesma coisa que o boost::any ( https://theboostcpplibraries.com/boost.any )

Veja um exemplo:


// g++ -o teste teste.cpp -Wall -O2 -std=c++17
#include <iostream>
#include <vector>
#include <any>
#include <string>

using namespace std;

int main()
{
int a = 10;
float b = 3.14;
bool c = true;
string d = "Hello World!";

vector<any> vec {a, b, c, d}; // este vector<any> contém int, float, bool e string !!!

for (auto& elem: vec) { // print o tipo de elem (i = integer, f = float, b = bool)
cout << elem.type().name() << endl;
}
cout << endl;

// para acessar o elemento use any_cast
cout << any_cast<int>(vec[0]) << endl;
cout << any_cast<float>(vec[1]) << endl;
cout << boolalpha << any_cast<bool>(vec[2]) << endl;
cout << any_cast<string>(vec[3]) << endl;

return 0;
}


C++17 tem bastante coisa nova que é interessante, vale a pena dar uma olhada...


5. Re: Como criar array estilo C ou vector de objetos diferentes em C++?

Fernando
phoemur

(usa Debian)

Enviado em 08/01/2018 - 20:36h

Aqui com std::variant do C++17, que se comporta mais ou menos como um union.
http://en.cppreference.com/w/cpp/utility/variant

Se você tiver um número definido de tipos que seu container deve armazenar, talvez std::variant seja mais adequado que std::any


// g++ -o teste teste.cpp -Wall -O2 -std=c++17
#include <iostream>
#include <vector>
#include <string>
#include <variant>

using namespace std;

int main()
{
int a = 10;
float b = 3.14;
string c = "Hello World!";

using cont = variant<int, float, string>;

vector<cont> vec {a, b, c}; // esse vector contém int, float e string

for (auto& elem: vec) {
// testa o tipo de cada elemento e imprime
if (holds_alternative<int>(elem)) {
cout << get<int>(elem) << endl;
}
else if (holds_alternative<float>(elem)) {
cout << get<float>(elem) << endl;
}
else if (holds_alternative<string>(elem)) {
cout << get<string>(elem) << endl;
}
}

return 0;
}


std::variant também veio no C++17


6. Re: Como criar array estilo C ou vector de objetos diferentes em C++?

Fernando
phoemur

(usa Debian)

Enviado em 08/01/2018 - 20:41h

Tanto std::any como std::variant são melhores que a abordagem usando ponteiros void*, pois eles respeitam o sistema de tipos e jogam uma exceção caso você faça uma conversão ilegal...
Já com ponteiros void* você tem que ter muito cuidado na hora de fazer o cast/conversão...

https://stackoverflow.com/questions/8757495/why-is-boostany-better-than-void

int i = 5;
void* p = &i;
static_cast<double*>(p); //Compiler doesn't complain. Undefined Behavior.
std::any a;
a = i;
std::any_cast<double>(a); //throws, which is good



7. Re: Como criar array estilo C ou vector de objetos diferentes em C++?

Paulo
paulo1205

(usa Ubuntu)

Enviado em 09/01/2018 - 02:17h

Obrigado, phoemur, por me atualizar. Eu estou meio desconectado do C++17. Sem dúvida, suas alternativas são melhores.

Contudo, continua sendo necessário que o nosso amigo mantenha o controle do que vai em cada posição do vetor. Caso contrário, as invocações à função std::any_cast() (ou às funções, visto que é um template) falharão.






Patrocínio

Site hospedado pelo provedor RedeHost.
Linux banner

Destaques

Artigos

Dicas

Tópicos

Top 10 do mês

Scripts