Note:
- In base class, even if not explicitly defined copy constructor and overloaded op=, derived class still is able to revolk defaut ones. (condition: no dynamic memory used in base class)
- Need to explicitly use methods of base class,
eg. Cd::Cd(d);//copy constructor of base class
Cd::operator=();//overloaed op= of base class
classic.h
#ifndef CD_H_
#define CD_H_
// base class
class Cd // represents a CD disk
{
private:
char performers[50];
char label[20];
int selections; // number of selections
double playtime; // playing time in minutes
public:
Cd(const char * s1, const char * s2, int n, double x);
Cd();
virtual ~Cd() {};// keep it or not, both are OK,it do nothing
virtual void Report() const; // reports all CD data
/*
use defaut copy construtor and op=
virtual Cd & operator=(const Cd & d);
*/
};
class Classic :public Cd
{
private:
// place constructor in private to level up safety,is not right
// dirived class is not able to revolk
char* ps;// use dynamic memory
public:
Classic();
Classic(const char*pt, const char * s1, const char * s2, int n, double x);
Classic(const Classic& d);
virtual ~Classic()
{
delete[]ps;
}; // inline function
virtual void Report() const; // reports all CD data
virtual Classic & operator=(const Classic & d);
};
#endif
// newly added data-member,if use dynamic memory,shall keep copy constructor and op=
// if use char array[],not necessary to keep
classic.cpp
#include<iostream>
#include"classic.h"
using std::cout;
using std::endl;
// *******implementations for Cd*******
Cd::Cd(const char * s1, const char * s2, int n, double x)
{
strcpy_s(performers, strlen(s1) + 1, s1);
strcpy_s(label, strlen(s2) + 1, s2);
selections = n;
playtime = x;
}
// ignore copy constructor, use default copy constructor to shallow copy is enough
Cd::Cd()
{
performers[0] = '\0';
label[0] = '\0';
selections = 0;
playtime = 0.0;
}
void Cd::Report() const
{
cout << "\nThe disk details: \n"
<< "Performers: ";
for (int i = 0; i < 50 && performers[i] != '\0'; i++)
{
cout << performers[i];
}
cout << "\nSelections: " << selections << endl;
cout << "Playtime: " << playtime << endl;
}
// *******implementations for Classic*******
Classic::Classic():Cd()
{
ps = nullptr;
}
Classic::Classic(const char* m, const char * s1, const char * s2, int n, double x):Cd(s1,s2,n,x)
{
int len = strlen(m) + 1;
ps = new char[len];
strcpy_s(ps, len, m);
}
// revolk default copy constructor
Classic::Classic(const Classic& d)
{
Cd::Cd(d);
int len = strlen(d.ps) + 1;
ps = new char[len];
strcpy_s(ps, len, d.ps);
}
void Classic::Report() const
{
// never re-do what base class funcions alreay has done
// explicit revolk
Cd::Report();
for (unsigned int i = 0; i < strlen(ps) && ps[i] != '\0'; i++)
cout << ps[i];
cout << endl << endl;
}
// auto revolk defaut op=?
Classic & Classic::operator=(const Classic & d)
{
Cd::operator=(d);
int len = strlen(d.ps) + 1;
ps = new char[len];
strcpy_s(ps, len, d.ps);
return *this;
}
main
#include <iostream>
using namespace std;
#include "classic.h" // which will contain #include cd.hProgramming Exercises 781
void Bravo(const Cd & disk);
int main()
{
Cd c1("Beatles", "Capitol", 14, 35.5);
Classic c2 = Classic("Piano Sonata in B flat, Fantasia in C",
"Alfred Brendel", "Philips", 2, 57.17);
Cd *pcd = &c1;
cout << "Using object directly:\n";
c1.Report(); // use Cd method
c2.Report(); // use Classic method
cout << "Using type cd * pointer to objects:\n";
pcd->Report(); // use Cd method for cd object
pcd = &c2;
pcd->Report(); // use Classic method for classic object
cout << "Calling a function with a Cd reference argument:\n";
Bravo(c1);
Bravo(c2);
cout << "Testing assignment: \n";
Classic copy;
copy = c2;
copy.Report();
cin.get();
return 0;
}
void Bravo(const Cd & disk)
{
disk.Report();
}