Pergunta

Considere estas classes.

class Base
{
   ...
};

class Derived : public Base
{
   ...
};

Esta função

void BaseFoo( std::vector<Base*>vec )
{
    ...
}

E, finalmente, a minha vector

std::vector<Derived*>derived;

Eu quero passar derived a função BaseFoo, mas o compilador não me deixa. Como faço para resolver isso, sem copiar todo o vector a um std::vector<Base*>?

Foi útil?

Solução

vector<Base*> e vector<Derived*> são tipos não relacionados, para que você não pode fazer isso. Isto é explicado no C ++ FAQ aqui .

Você precisa mudar sua variável de um vector<Derived*> a um vector<Base*> e inserir objetos Derived para ele.

Além disso, para evitar copiar o vector desnecessariamente, você deve passá-lo por const-referência, não pelo valor:

void BaseFoo( const std::vector<Base*>& vec )
{
    ...
}

Finalmente, para evitar vazamentos de memória, e fazer o seu código de exceção de segurança, considere usar um recipiente concebido para objetos alocados-heap punho, por exemplo:

#include <boost/ptr_container/ptr_vector.hpp>
boost::ptr_vector<Base> vec;

Como alternativa, altere o vector para manter um ponteiro inteligente em vez de usar ponteiros crus:

#include <memory>
std::vector< std::shared_ptr<Base*> > vec;

ou

#include <boost/shared_ptr.hpp>
std::vector< boost::shared_ptr<Base*> > vec;

Em cada caso, você precisa modificar a sua função BaseFoo em conformidade.

Outras dicas

Em vez de passar o objeto recipiente (vector<>), passar em begin e end iterators como o resto dos algoritmos STL. A função que os recebe vai ser templated, e não importará se você passar em Derivado * ou base *.

Este problema ocorre em linguagens que têm recipientes mutáveis ??programação. Você não pode passar em torno de um saco mutável de maçãs como um saco de frutas, porque você não pode ter certeza que alguém não coloca um limão em que o saco de frutas, depois que ele se qualifica não mais como um saco de maçãs. Se o saco de maçãs que não foram mutável, passá-lo em torno de como uma sacola de frutas seria ótimo. Procurar covariância / contravariance.

uma opção é usar um modelo

template<typename T>
void BaseFoo( const std::vector<T*>& vec)
{
 ...
}

A desvantagem é que a implementação tem de ser no cabeçalho e você vai ficar um pouco inchaço código. Você vai acabar com diferentes funções seja instanciado para cada tipo, mas o código permanece o mesmo. Dependendo do caso de uso é uma solução rápida e suja.

Editar, devo observar a razão precisamos de um modelo aqui é porque estamos tentando escrever o mesmo código para os tipos não relacionados como observado por vários outros cartazes. Os modelos permitem que você resolver estes problemas exatos. Eu também atualizei para usar uma referência const. Você também deve passar objetos "pesados" como um vetor por referência const quando você não precisa de uma cópia, que é basicamente sempre.

Geralmente você iria começar com um recipiente de ponteiros de base, não o contrário.

resposta de Matt Preço de cima, uma vez que você sabe de antemão quais os tipos que você deseja usar com a função, você pode declarar o modelo de função no arquivo de cabeçalho e, em seguida, adicione instantiations explícitas para esses tipos:

// BaseFoo.h
template<typename T>
void BaseFoo( const std::vector<T*>& vec);

// BaseFoo.cpp
template<typename T>
void BaseFoo( const std::vector<T*>& vec);
{
 ...
}

// Explicit instantiation means no need for definition in the header file.
template void BaseFoo<Base> ( const std::vector<Base*>& vec );
template void BaseFoo<Derived> ( const std::vector<Derived*>& vec );

Se você lidar com uma biblioteca de terceiros, e esta é sua única esperança, então você pode fazer isso:

BaseFoo (*reinterpret_cast<std::vector<Base *> *>(&derived));

Caso contrário, corrigir o seu código com um dos outros suggesstions.

Se std::vector suportado o que você está pedindo, então seria possível derrotar o sistema de tipo C ++ sem usar moldes (EDIT: ligação de ChrisN às negociações C ++ FAQ Lite sobre a mesma questão):

class Base {};
class Derived1 : public Base {};
class Derived2 : public Base {};

void pushStuff(std::vector<Base*>& vec) {
    vec.push_back(new Derived2);
    vec.push_back(new Base);
}

...
std::vector<Derived1*> vec;
pushStuff(vec); // Not legal
// Now vec contains a Derived2 and a Base!

Desde a sua função BaseFoo() leva o vetor por valor, não pode modificar o vector original que você passou em, então o que eu escrevi não seria possível. Mas se é preciso uma referência não-const e você usar reinterpret_cast<std::vector<Base*>&>() para passar o seu std::vector<Derived*>, você pode não obter o resultado que você quer, e seu programa pode falhar.

matrizes Java apoiar covariant subtipos , e isso requer Java para fazer um tipo de tempo de execução verificar cada vez que você armazenar um valor em uma matriz. Isso também é indesejável.

Eles são tipos não relacionados - você não pode.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top