Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C++: Inheritance, assigning

I'm learning C++, currently I'm at inheritance of classes and dynamic memory allocation for objects. I'm doing some exercises, and right now I'm stuck on some strange crash of my application.

The problem lies in assigning derived class to new object. Everything looks fine, until destructors are starting to work, I analyzed everything and I cannot find mistake. Code should be pretty simple, class cd stores simple data and "classic" is adding one field.

(The main problem is that app is crashing at the end)

This is source code I hope someone will be able to help me

#ifndef CLASSIC_H_
#define CLASSIC_H_

class Cd
{
private:
    char* performers;
    char* label;
    int selection;
    double playtime;
public:
    Cd(char* s1, char* s2, int n, double x);
    Cd(const Cd& d);
    Cd();
    virtual ~Cd();
    virtual void Report() const;
    Cd& operator=(const Cd& d);
};

class Classic : public Cd
{
private:
    char* maintrack;
public:
    Classic(char* mt, char* s1, char* s2, int n, double x);
    Classic();
    Classic(const Classic& c);
    Classic(char* mt, const Cd& d);
    virtual void Report() const;
    virtual ~Classic();
    Classic& operator=(const Classic& c);
};

#endif



using std::strcpy;
Cd::Cd(char* s1, char* s2, int n, double x)
{

    performers = new char[strlen(s1) + 1];
    strcpy(performers, s1);

    label = new char[strlen(s2) + 1];
    strcpy(label, s2);

    selection = n;
    playtime = x;
}

Cd::Cd(const Cd& d)
{
    performers = new char[strlen(d.performers) + 1];
    strcpy(performers, d.performers);

    label = new char[strlen(d.label) + 1];
    strcpy(label, d.label);

    selection = d.selection;
    playtime = d.playtime;
}    

Cd::~Cd()
{

    delete [] performers;
    delete [] label;
}

Cd::Cd()
{
    performers = new char[1];
    performers[0] = '\0';

    label = new char[1];
    label[0] = '\0';

    selection = 0;
    playtime = 0;
}


Cd& Cd::operator=(const Cd& d)
{
    if (this == &d)
        return *this;

    delete [] performers;
    delete [] label;

    performers = new char[strlen(d.performers) + 1];
    strcpy(performers, d.performers);

    label = new char[strlen(d.label) + 1];
    strcpy(label, d.label);

    selection = d.selection;
    playtime = d.playtime;
    return *this;
}


void Cd::Report() const
{
    using namespace std;
    cout << performers << endl;
    cout << label << endl;
    cout << selection << endl;
    cout << playtime << endl;
}


Classic::Classic(char* mt, char* s1, char* s2, int n, double x)
    : Cd(s1, s2, n, x)
{
    maintrack = new char[strlen(mt) + 1];
    strcpy(maintrack, mt);
}

Classic::Classic() : Cd()
{
    maintrack = new char[1];
    maintrack[0] = '\0';
}

Classic::Classic(const Classic& c) : Cd(c)
{
    maintrack = new char[strlen(c.maintrack) + 1];
    strcpy(maintrack, c.maintrack);
}

Classic::Classic(char* mt, const Cd& d) : Cd(d)
{
    maintrack = new char[strlen(mt) + 1];
    strcpy(maintrack, mt);
}

void Classic::Report() const
{
    Cd::Report();
    std::cout << maintrack << std::endl;
}

Classic::~Classic()
{
    delete [] maintrack;
}

Classic& Classic::operator=(const Classic& c)
{
    if (this == &c)
        return *this;

    Cd::operator=(c);
    delete [] maintrack;

    maintrack = new char[strlen(c.maintrack)];
    strcpy(maintrack, c.maintrack);

    return *this;
}







#include <iostream>
#include "classic.h"
#include <cstdlib>
using namespace std;

void Bravo(const Cd& disk);

int main()
{
    Cd c1("Beatles", "Capitol", 14, 35.5);
    Classic c2 = Classic("Sonata fortepianowa B-dur, Fantazja C-moll",
                         "Alfred Brendel", "Philips", 2, 57.17);


    Classic copy;
    copy = c2;

    copy.Report();


    system("pause");


    return 0;
}

void Bravo(const Cd& disk)
{
    disk.Report();
}
like image 773
ashur Avatar asked Sep 29 '26 03:09

ashur


2 Answers

The problem is in your copy constructor for Classic. However, this just highlights the perils of doing your own string manipulation. I'd suggest rewriting this entire exercise with no char* and using std::string instead.

Classic& Classic::operator=(const Classic& c)
{
    if (this == &c)
        return *this;

    Cd::operator=(c);
    delete [] maintrack;

        // you need strlen(c.maintrack) + 1
    maintrack = new char[strlen(c.maintrack)];
    strcpy(maintrack, c.maintrack);

    return *this;
}
like image 118
Chad Avatar answered Sep 30 '26 15:09

Chad


Possible memory corruption in Classic& Classic::operator=(const Classic& c) :

maintrack = new char[strlen(c.maintrack)];
strcpy(maintrack, c.maintrack);

replace with:

maintrack = new char[strlen(c.maintrack) + 1];
strcpy(maintrack, c.maintrack);

That said, why exactly aren't you just using the string class that's part of the standard library? It would save you this and many other headaches. It does all of the memory management, null termination, etc. all automatically.

string maintrack;
char * derp = "derp";
maintrack = derp; // valid
maintrack = "derp"; // valid
maintrack = another_string; // valid
like image 37
Wug Avatar answered Sep 30 '26 15:09

Wug



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!