简体   繁体   中英

Polymorphism with copy constructor

Here is the code I use. I'd like to know if what I did is correct and safe. Normally it compiles and the tests I did are successful. But as it is the first time that I use dynamic_cast and static_cast , I'd like to be sure that I didn't miss anything.

Can you please check :

  • that I don't forget to delete any pointer (I don't really understand what my clone method does...)
  • if I use correctly dynamic_cast and static_cast
  • that there is not a more efficient of doing it

But my main concern is that I correctly implement the clone() method

Thanks a lot!!!

Edit

Thanks to some answer I realized that I should redesign my code. So I could get rid of this piece of code...

the .hpp file:

#include <vector>

/*!Base class that will never be instantiate. It provides a way to create
 * GenericData with defferent type. */
class Data{
    public:
        /*!Constructor*/
        Data(std::string name):name_(name){}
        /*!Destructor, must be virtual*/
        virtual ~Data(){};

        /*!Method that allows a copy of the derived class*/
        virtual Data* clone() const = 0;

    protected:
        std::string name_;//!< Name of the (Generic)Data 

};

/*!Derived class that can contain any one value of any type and of name name_*/
template<typename Type>
class GenericData : public Data{
    public:
        /*!Constructor*/
        GenericData(std::string name, Type t): Data(name), t_(t){}
        /*!Destructor*/
        ~GenericData(){};

        /*!Method that implements*/
        GenericData<Type>* clone() const { return new GenericData<Type>(static_cast<GenericData<Type> const&>(*this) );}

        /*!Returns the value of the data*/
        Type const& get_val() const {return t_;}

    private:
        Type t_;//!< Value of the GenericData
};

/*!Contains a vector of Data*, can store diffrent GenericData*/
class Container{
    public:
        Container(){};
        Container(Container const& c){ 
            for(unsigned int i(0);i<c.data_.size();i++){
                data_.push_back((c.data_[i])->clone());
            }
        }
        ~Container(){
            for(unsigned int i(0);i<data_.size();i++){
                delete data_[i];
                data_[i] = NULL;
            }
        }

        /*!Add one GenericData<Type> of value t and named name*/
        template<typename Type>
            void set(std::string name, Type const& t){data_.push_back(new GenericData<Type>(name,t));}

        /*!Returns the value GenericData<Type>::t_ named name*/
        template<typename Type>
            Type get(std::string name) const;

    private:
        std::vector<Data*> data_;
};

template<typename Type>
void Container::set(std::string name, Type const& t){
    data_.push_back(new GenericData<Type>(name,t));
}

template<typename Type>
Type Container::get(std::string name) const {
    for(unsigned int i(0);i<data_.size();i++){
        if(data_[i]->get_name()==name){
            return dynamic_cast< GenericData<Type> *>(data_[i])->get_val();
        }
    }
    std::cerr<<"Container : get(string name) : no data with name "<<name<<std::endl;
    return 0;
}
GenericData<Type>* clone() const{
    return new GenericData<Type>(static_cast<GenericData<Type> const&>(*this) );
}

Here you don't need to use static_cast because type of *this is already const GenericData<Type>& .

================================================

    if(data_[i]->get_name()==name){
        return dynamic_cast< GenericData<Type> *>(data_[i])->get_val();
    }  

Here you need to check whether dynamic_cast returns null pointer. null pointer will be returned if data_[i] is not of type GenericData<Type>* (or if it's not a pointer to some type derived from GenericData<Type> )

=============================================
You also need to define Container::operator= . If you don't define it the compiler will generate it for you and vector<Data*> can be improperly copied.

=============================================

Also my advice is to use std::shared_ptr<Data> (of boost::shared_ptr<Data> if you use C++98) or std::unique_ptr<> instead of Data* to avoid manual object deletion and related potential memory leaks.

Disregarding that you are re-implementing std::map in a terrible way (do you really want to allow storing GenericData<string> and GenericData<float> in the same container?), your clone method should not even compile because you are invoking GenericData<T> 's copy constructor without having defined one. How about this simple and readable alternative:

Data* clone() const {
    return new GenericData<Type>(name_, t_);
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM