Clone Methode



  • Ich bin in meinem Buch gerade bei Clone Methoden angelangt, das man Kopierkonstruktoren ja nicht virtuell deklarieren kann. Aber irgendwie blick ichda noch nicht so richtig durch. Hier wäre mal ein Beispiel mit einer Clone Methode:

    #include <iostream>
    using namespace std;
    
    class Mammal
    {
        public:
        Mammal(int Age,int Weight);
        Mammal(const Mammal &rhs);
        virtual ~Mammal();
        int GetAge() const {return *itsAge;}
        int GetWeight() const {return *itsWeight;}
        virtual void Speak() const {cout << "Mammal spricht\n";}
        virtual Mammal* Clone() const {return new Mammal(*this);}
        private:
        int *itsAge;
        int *itsWeight;
    };
    
    Mammal::Mammal(int Age,int Weight)
    :itsAge(new int(Age)),itsWeight(new int(Weight))
    {
    
    }
    
    Mammal::Mammal(const Mammal &rhs)
    :itsAge(new int(rhs.GetAge())),itsWeight(new int(rhs.GetWeight()))
    {
        cout << "Mammal Kopierkonstruktor\n";
    }
    
    Mammal::~Mammal()
    {
        delete itsAge;
        delete itsWeight;
    }
    
    class Cat : public Mammal
    {
        public:
        Cat(int Age,int Weight);
        Cat(const Cat &rhs);
        virtual ~Cat();
        void Speak() const {cout << "Miau miau\n";}
        virtual Cat* Clone() const {return new Cat(*this);}
    };
    
    Cat::Cat(int Age,int Weight)
    :Mammal(Age,Weight)
    {
    
    }
    
    Cat::Cat(const Cat &rhs)
    :Mammal(rhs)
    {
        cout << "Cat Kopierkonstruktor\n";
    }
    
    Cat::~Cat()
    {
    
    }
    
    class Dog : public Mammal
    {
        public:
        Dog(int Age,int Weight);
        Dog(const Dog &rhs);
        virtual ~Dog();
        void Speak() const {cout << "Wuff wuff\n";}
        virtual Dog* Clone() const {return new Dog(*this);}
    };
    
    Dog::Dog(int Age,int Weight)
    :Mammal(Age,Weight)
    {
    
    }
    
    Dog::Dog(const Dog &rhs)
    :Mammal(rhs)
    {
        cout << "Dog Kopierkonstruktor\n";
    }
    
    Dog::~Dog()
    {
    
    }
    
    const int ANIMALS=3;
    
    int main()
    {
        int choice;
        Mammal *Tier[ANIMALS];
        Mammal *OtherTier[ANIMALS];
        Mammal *ptr;
        for (int i=0;i<ANIMALS;i++)
        {
            cout << "Dog(1) Cat(2) Mammal(3)\n";
            cin >> choice;
            switch(choice)
            {
                case 1:
                ptr=new Dog(3,4);
                break;
                case 2:
                ptr=new Cat(7,4);
                break;
                case 3:
                ptr=new Mammal(1,4);
                break;
            }
            Tier[i]=ptr;
        }
        for (int i=0;i<ANIMALS;i++)
        {
            Tier[i]->Speak();
            OtherTier[i]=Tier[i]->Clone();
            //OtherTier[1]=Tier[i]; //warum nicht so? Warum wird hier nicht der Kopierkonstruktor aufgerufen?
        }
        for (int i=0;i<ANIMALS;i++)
        {
            cout << OtherTier[i]->GetAge() << "\n";
        }
    
        return 0;
    }
    

    AUSGABE:

    Dog(1) Cat(2) Mammal(3)
    1
    Dog(1) Cat(2) Mammal(3)
    2
    Dog(1) Cat(2) Mammal(3)
    3
    Wuff wuff
    Mammal Kopierkonstruktor
    Dog Kopierkonstruktor
    Miau miau
    Mammal Kopierkonstruktor
    Cat Kopierkonstruktor
    Mammal spricht
    Mammal Kopierkonstruktor
    3
    7
    1

    Zeile 121 hab ich mal auskommentiert, so würde es ja auch gehen oder? Aber wenn ich es so mach, dann wird irgendwie der Kopierkonstruktor nicht aufgerufen, somit schätz ich mal das bei dem neuen Objekt die Zeiger auf die gleiche Speicherstelle verwiesen wie bei dem alten Objekt (das is ja der eigentliche Grud warum man Kopierkonstruktoren verwendet).
    Aber so ganz verstehe ich es noch nicht, so würde es ja auch funktionieren:

    #include <iostream>
    using namespace std;
    
    class Mammal
    {
        public:
        Mammal(int Age,int Weight);
        Mammal(const Mammal &rhs);
        virtual ~Mammal();
        int GetAge() const {return *itsAge;}
        int GetWeight() const {return *itsWeight;}
        virtual void Speak() const {cout << "Mammal spricht\n";}
        virtual Mammal* Clone() const {return new Mammal(*this);}
        private:
        int *itsAge;
        int *itsWeight;
    };
    
    Mammal::Mammal(int Age,int Weight)
    :itsAge(new int(Age)),itsWeight(new int(Weight))
    {
    
    }
    
    Mammal::Mammal(const Mammal &rhs)
    :itsAge(new int(rhs.GetAge())),itsWeight(new int(rhs.GetWeight()))
    {
        cout << "Mammal Kopierkonstruktor\n";
    }
    
    Mammal::~Mammal()
    {
        delete itsAge;
        delete itsWeight;
    }
    
    class Cat : public Mammal
    {
        public:
        Cat(int Age,int Weight);
        Cat(const Cat &rhs);
        virtual ~Cat();
        void Speak() const {cout << "Miau miau\n";}
        virtual Cat* Clone() const {return new Cat(*this);}
    };
    
    Cat::Cat(int Age,int Weight)
    :Mammal(Age,Weight)
    {
    
    }
    
    Cat::Cat(const Cat &rhs)
    :Mammal(rhs)
    {
        cout << "Cat Kopierkonstruktor\n";
    }
    
    Cat::~Cat()
    {
    
    }
    
    class Dog : public Mammal
    {
        public:
        Dog(int Age,int Weight);
        Dog(const Dog &rhs);
        virtual ~Dog();
        void Speak() const {cout << "Wuff wuff\n";}
        virtual Dog* Clone() const {return new Dog(*this);}
    };
    
    Dog::Dog(int Age,int Weight)
    :Mammal(Age,Weight)
    {
    
    }
    
    Dog::Dog(const Dog &rhs)
    :Mammal(rhs)
    {
        cout << "Dog Kopierkonstruktor\n";
    }
    
    Dog::~Dog()
    {
    
    }
    
    const int ANIMALS=3;
    
    int main()
    {
        int choice;
        Mammal *Tier[ANIMALS];
        Mammal *OtherTier[ANIMALS];
        Mammal *ptr;
        for (int i=0;i<ANIMALS;i++)
        {
            cout << "Dog(1) Cat(2) Mammal(3)\n";
            cin >> choice;
            switch(choice)
            {
                case 1:
                ptr=new Dog(3,4);
                break;
                case 2:
                ptr=new Cat(7,4);
                break;
                case 3:
                ptr=new Mammal(1,4);
                break;
            }
            Tier[i]=ptr;
        }
        for (int i=0;i<ANIMALS;i++)
        {
            Tier[i]->Speak();
            //OtherTier[i]=Tier[i]->Clone();
            OtherTier[1]=Tier[i]; //<-- um die Stelle hier gehts!!!!
        }
        for (int i=0;i<ANIMALS;i++)
        {
            cout << OtherTier[i]->GetAge() << "\n";
        }
    
        return 0;
    }
    

    Mh doch der schein trügt, wenn ich das ablaufen lasse und bei den Eingaben wieder 1,2 und 3 eingebe kommt zum Schluss so n Windows Fenster "...musste abgebrochen werden...". Und der Kopierkonstruktor wird auch nicht aufgerufen? Mh warum kommt da ein Windows Error, nur weil ich keine Clone Methode anwende? Ich mein auch wenn der Kopierkonstruktor nicht aufgerufen wird dann müsste das Programm baer doch trotzdem laufen? Ahhhhh!!! Kann mir das mal einer erklären, weil in meinem Buch ist das nur ganz kurz beschrieben (das Buch ist teilweise echt sch**** ich rate euch kauft euch nie "Jetzt lernen ich C++", aber na ja jetzt hab ichs halt und muss das beste daraus machen, war ja teuer genug 😞 ).
    Also ich hoffe es weiß von euch jemand weiter, der mir das nochmal genau erklären kann. Dankeschön schon mal im Voraus.



  • Der Zugriffsfehler ist wegen

    OtherTier[[b]1[/b]]=Tier[i]; //<-- um die Stelle hier gehts!!!!
    

    sollte wohl ein i sein.
    Kurt



  • Oh äh peinlich, peinlich :D, aber ich verstehe immer noch nicht warum kein Kopierkonstruktor aufgerufen wird, die Ausgabe wäre dann:

    Dog(1) Cat(2) Mammal(3)
    1
    Dog(1) Cat(2) Mammal(3)
    2
    Dog(1) Cat(2) Mammal(3)
    3
    Wuff wuff
    Miau miau
    Mammal spricht
    3
    7
    1
    

    Also macht der nur eine flache Kopie oder? Also verweisen "altes Objekt" und "neues Objekt" auf die gleiche Speicherstelle im Heap? Deshalb die Clone Methode oder was sollte sonst der Sinn einer Clone Mttohde sein? Also Clone Methode vs. Kopierkonstruktor würde ich mal sagen. Na ja wer mehr weiß als ich soll es mir doch bitte erklären. Dankeschön schon mal im Voraus.



  • In deinem Beispiel kopierst du keine Objekte, nur Pointer, daher wird auch kein Kopierkonstruktor deiner Klassen aufgerufen. Auch wenns Objekte wären, würde nicht der Kopierkonstruktor aufgerufen werden sondern der Zuweisungs Operator.
    Kurt
    Edit:
    Denke du willst sowas

    for (int i=0;i<ANIMALS;i++)
        {
            Tier[i]->Speak();
            OtherTier[i]=Tier[i]->Clone();
        }
    


  • Ja aber ich verstehe nicht wo hier der Unterschied ist:
    1.

    #include <iostream> 
    using namespace std; 
    
    class Mammal 
    { 
        public: 
        Mammal(int Age,int Weight); 
        Mammal(const Mammal &rhs); 
        virtual ~Mammal(); 
        int GetAge() const {return *itsAge;} 
        int GetWeight() const {return *itsWeight;} 
        virtual void Speak() const {cout << "Mammal spricht\n";} 
        virtual Mammal* Clone() const {return new Mammal(*this);} 
        private: 
        int *itsAge; 
        int *itsWeight; 
    }; 
    
    Mammal::Mammal(int Age,int Weight) 
    :itsAge(new int(Age)),itsWeight(new int(Weight)) 
    { 
    
    } 
    
    Mammal::Mammal(const Mammal &rhs) 
    :itsAge(new int(rhs.GetAge())),itsWeight(new int(rhs.GetWeight())) 
    { 
        cout << "Mammal Kopierkonstruktor\n"; 
    } 
    
    Mammal::~Mammal() 
    { 
        delete itsAge; 
        delete itsWeight; 
    } 
    
    class Cat : public Mammal 
    { 
        public: 
        Cat(int Age,int Weight); 
        Cat(const Cat &rhs); 
        virtual ~Cat(); 
        void Speak() const {cout << "Miau miau\n";} 
        virtual Cat* Clone() const {return new Cat(*this);} 
    }; 
    
    Cat::Cat(int Age,int Weight) 
    :Mammal(Age,Weight) 
    { 
    
    } 
    
    Cat::Cat(const Cat &rhs) 
    :Mammal(rhs) 
    { 
        cout << "Cat Kopierkonstruktor\n"; 
    } 
    
    Cat::~Cat() 
    { 
    
    } 
    
    class Dog : public Mammal 
    { 
        public: 
        Dog(int Age,int Weight); 
        Dog(const Dog &rhs); 
        virtual ~Dog(); 
        void Speak() const {cout << "Wuff wuff\n";} 
        virtual Dog* Clone() const {return new Dog(*this);} 
    }; 
    
    Dog::Dog(int Age,int Weight) 
    :Mammal(Age,Weight) 
    { 
    
    } 
    
    Dog::Dog(const Dog &rhs) 
    :Mammal(rhs) 
    { 
        cout << "Dog Kopierkonstruktor\n"; 
    } 
    
    Dog::~Dog() 
    { 
    
    } 
    
    const int ANIMALS=3; 
    
    int main() 
    { 
        int choice; 
        Mammal *Tier[ANIMALS]; 
        Mammal *OtherTier[ANIMALS]; 
        Mammal *ptr; 
        for (int i=0;i<ANIMALS;i++) 
        { 
            cout << "Dog(1) Cat(2) Mammal(3)\n"; 
            cin >> choice; 
            switch(choice) 
            { 
                case 1: 
                ptr=new Dog(3,4); 
                break; 
                case 2: 
                ptr=new Cat(7,4); 
                break; 
                case 3: 
                ptr=new Mammal(1,4); 
                break; 
            } 
            Tier[i]=ptr; 
        } 
        for (int i=0;i<ANIMALS;i++) 
        { 
            Tier[i]->Speak(); 
            OtherTier[i]=Tier[i]->Clone(); //<--
        } 
        for (int i=0;i<ANIMALS;i++) 
        { 
            cout << OtherTier[i]->GetAge() << "\n"; 
        } 
    
        return 0; 
    }
    

    oder so
    2.

    #include <iostream> 
    using namespace std; 
    
    class Mammal 
    { 
        public: 
        Mammal(int Age,int Weight); 
        Mammal(const Mammal &rhs); 
        virtual ~Mammal(); 
        int GetAge() const {return *itsAge;} 
        int GetWeight() const {return *itsWeight;} 
        virtual void Speak() const {cout << "Mammal spricht\n";} 
        virtual Mammal* Clone() const {return new Mammal(*this);} 
        private: 
        int *itsAge; 
        int *itsWeight; 
    }; 
    
    Mammal::Mammal(int Age,int Weight) 
    :itsAge(new int(Age)),itsWeight(new int(Weight)) 
    { 
    
    } 
    
    Mammal::Mammal(const Mammal &rhs) 
    :itsAge(new int(rhs.GetAge())),itsWeight(new int(rhs.GetWeight())) 
    { 
        cout << "Mammal Kopierkonstruktor\n"; 
    } 
    
    Mammal::~Mammal() 
    { 
        delete itsAge; 
        delete itsWeight; 
    } 
    
    class Cat : public Mammal 
    { 
        public: 
        Cat(int Age,int Weight); 
        Cat(const Cat &rhs); 
        virtual ~Cat(); 
        void Speak() const {cout << "Miau miau\n";} 
        virtual Cat* Clone() const {return new Cat(*this);} 
    }; 
    
    Cat::Cat(int Age,int Weight) 
    :Mammal(Age,Weight) 
    { 
    
    } 
    
    Cat::Cat(const Cat &rhs) 
    :Mammal(rhs) 
    { 
        cout << "Cat Kopierkonstruktor\n"; 
    } 
    
    Cat::~Cat() 
    { 
    
    } 
    
    class Dog : public Mammal 
    { 
        public: 
        Dog(int Age,int Weight); 
        Dog(const Dog &rhs); 
        virtual ~Dog(); 
        void Speak() const {cout << "Wuff wuff\n";} 
        virtual Dog* Clone() const {return new Dog(*this);} 
    }; 
    
    Dog::Dog(int Age,int Weight) 
    :Mammal(Age,Weight) 
    { 
    
    } 
    
    Dog::Dog(const Dog &rhs) 
    :Mammal(rhs) 
    { 
        cout << "Dog Kopierkonstruktor\n"; 
    } 
    
    Dog::~Dog() 
    { 
    
    } 
    
    const int ANIMALS=3; 
    
    int main() 
    { 
        int choice; 
        Mammal *Tier[ANIMALS]; 
        Mammal *OtherTier[ANIMALS]; 
        Mammal *ptr; 
        for (int i=0;i<ANIMALS;i++) 
        { 
            cout << "Dog(1) Cat(2) Mammal(3)\n"; 
            cin >> choice; 
            switch(choice) 
            { 
                case 1: 
                ptr=new Dog(3,4); 
                break; 
                case 2: 
                ptr=new Cat(7,4); 
                break; 
                case 3: 
                ptr=new Mammal(1,4); 
                break; 
            } 
            Tier[i]=ptr; 
        } 
        for (int i=0;i<ANIMALS;i++) 
        { 
            Tier[i]->Speak(); 
            OtherTier[i]=Tier[i];  //<--
        } 
        for (int i=0;i<ANIMALS;i++) 
        { 
            cout << OtherTier[i]->GetAge() << "\n"; 
        } 
    
        return 0; 
    }
    

    Bei "1." übergebe ich doch immer ein abgeleitetes Objekt von Mammal, oder das Mammal Objekt (immer als Zeiger), und bei "2." übergebe ich doch einfach das gesamte Mammal Objekt, bzw. die Adresse? Warum qird aber bei "1." der Kopierkonstruktor aufgerufen und bei "2." nicht? Dankeschön schon mal im Voraus.



  • Bei 1 erzeugst du mit Clone() ein neues Objekt ( eine Kopie ). Du hast jetzt also 6 Pointer auf verschiedene Objekte.
    Bei 2 weist du nur einem Pointer einen Pointer auf ein anderes Objekt zu. In beiden Arrays hast du jetzt die gleichen Pointer also nur 3 verschiedene Pointer.
    Kurt


Anmelden zum Antworten