- 以下面的类声明为基础:
class Cd{
private:
char performers[50];
char label[20];
int selections;
double playtime;
public:
Cd(char * s1, char * s2, int n, double x);
Cd(const Cd & d);
Cd();
~Cd();
void Report() const;
Cd & operator=(const Cd & d);
};
派生出一个Classic类,并添加一组char成员,用于存储指出CD中主要作品的字符串。修改上述声明,使基类的所有函数都是虚的。如果上述定义声明的某个方法并不需要,则请删除它。使用下面的程序测试您的产品:
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();
c2.Report();
cout << "Using type cd * pointer to objects:\n";
pcd->Report();
pcd = &c2;
pcd->Report();
cout << "Calling a function with a Cd reference argument:\n";
Bravo(c1);
Bravo(c2);
cout << "Testing assignment: ";
Classic copy;
copy = c2;
copy.Report();
return 0;
}
完善后我的答案:
#include <iostream>
#include <cstring>
using namespace std;
class Cd{
protected:
char performers[50];
char label[20];
int selections;
double playtime;
public:
Cd(char* s1, char* s2, int n, double x);
Cd();
virtual void Report() const;
virtual Cd& operator=(const Cd& d);
};
Cd::Cd(char * s1, char * s2, int n, double x): selections(n), playtime(x){
strcpy(performers, s1);
strcpy(label, s2);
}
Cd::Cd(){} //一定得写,很重要!不然会报错!
void Cd::Report()const {
cout << "performers: "<< performers << endl;
cout << "label: " << label << endl;
cout << "number of selections: " << selections << endl;
cout << "playing time in minutes: " << playtime << endl;
cout << endl;
}
Cd& Cd::operator=(const Cd& d){
strcpy(performers, d.performers);
strcpy(label, d.label);
selections = d.selections;
playtime = d.playtime;
return *this;
}
class Classic : public Cd{
protected:
char majorworkers[100];
public:
Classic(char* s1, char* s2, char* s3, int n, double x);
Classic();
void Report() const;
Classic& operator = (Classic& c);
};
Classic::Classic(char* s1, char* s2, char* s3, int n, double x): Cd(s2, s3, n, x){
strcpy(majorworkers, s1);
}
Classic::Classic() {} //一定得写,很重要!不然会报错!
void Classic::Report()const{
cout << "majorworkers: " << majorworkers << endl;
cout << "performers: "<< performers << endl;
cout << "label: " << label << endl;
cout << "number of selections: " << selections << endl;
cout << "playing time in minutes: " << playtime << endl;
cout << endl;
}
Classic& Classic::operator = (Classic& c){
strcpy(majorworkers, c.majorworkers);
Cd::operator=(c);
return *this;
}
void Bravo(const Cd & disk){
disk.Report();
}
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();
c2.Report();
cout << "Using type cd * pointer to objects:\n";
pcd->Report();
pcd = &c2;
pcd->Report();
cout << "Calling a function with a Cd reference argument:\n";
Bravo(c1);
Bravo(c2);
cout << "Testing assignment: ";
Classic copy;
copy = c2;
copy.Report();
return 0;
}
注意点:
- 重载赋值号的格式:point& operate = (const point& p) {x=p.x;y=p.y;return *this;}
- 如果我在基类定义了带参的构造函数,而主函数中用到了派生类的无参构造函数(就是指定义一个派生类的对象,未赋初值),那么该派生类和基类的无参构造函数都得写出来。为什么呢?
- 派生类的无参构造函数为什么必须得写?我还不是很清楚,百度也没查到为什么,但就是不行。
- 基类的无参构造函数必须得写,因为基类已经定义了带参的构造函数,当派生类的构造函数调用基类构造函数的时候就会调用显示定义的,如果说基类并未定义带参构造函数,派生类的构造函数将调用基类的默认构造函数。
- 类的display函数一般定义成const函数
- 将派生类对象的地址赋给基类指针时,如果基类的虚函数在该派生类被重新定义了,该指针调用该虚函数的时候调用的是派生类内的新定义的虚函数。
- 如果用到继承,基类的成员尽量定义为protected,不然派生类没法访问
- 完成练习1,但让两个类使用动态内存分配而不是长度固定的数组来记录字符串。
- 动态分配内存就涉及到new的使用,析构函数就要自己定义
- 这道题主要修改了类的构造函数、析构函数、还有重载运算符部分涉及到指针的部分。
注意点:
- strlen和sizeof的区别?在计算字符串长度的时候是否两个都能用?
- new一个字符型指针指向字符型数组的时候,长度如何计算?
- 接上一点,在带参的构造函数中,通过参数传递了字符数组,new了之后,如何将字符数组赋给字符指针,直接相等行不行?
贴一个带指针的重载赋值运算符改进的标准答案:
Cd & Cd::operator=(const Cd & d)
{
if (this == &d)
return *this;
delete [] label;
delete [] performers;
performers = new char[strlen(d.performers) + 1];
strcpy(performers, d.performers);
label = new char[strlen(d.label) + 1];
strcpy(label, d.label);
selections = d.selections;
playtime = d.playtime;
return *this;
}
- Benevolent Order of Programmers用来维护瓶装葡萄酒箱。为描述它,BOP Portmaster 设置了一个Port类,其声明如下:
#include < iost ream>
using namespace std;
class Port{
private:
char* brand;
char sty1e[20];
int bottles ;
public:
Port (const char* br = "none", const char* st = "none", int b = 0) ;
Port (const Port & p) ;
// copy const ructor
virtual ~Port(){ delete [] br and;}
Port & operator= (const Port & pl ;
Port & operator+=(int b) ;
// adds b to bottles .
Port & operator-=(int b) ;
// subtracts b from bottles, if a vailable
int BottleCount() const{ return bottles;]
virtual void Show() const;
friend ostream & operator<< (ostream & os,const Port & p) ;
};
show( )方法按下面的格式显示信息:
Brand: Gal1o
Kind: tawny
Bottles: 20
operator<<( )函数按下面的格式显示信息(末尾没有换行符):
Gallo,tawny, 20
PorMaster完成了Port 类的方法定义后派生了VintagePort 类,然后被解职—— 因为不小心将一瓶 45度Cockburn泼到了正在准备烤肉调料的人身上,VintagePort 类如下所示:
class VintagePort : public Port // style necessarily = "vintage"
private: .
char* nickname ;
// i.e.. "The Noble" or "0ld Velvet", etc.
int year;
// vintage year
public:
VintagePort() ;
VintagePort (const char* br, int b, const char* nn,int y);
Vint agePort (const VintagePort & vp) ;
~VintagePort{){ delete [] nickname ;}
VintagePort & operator= lconst VintagePort & vp) ;
void Show() const ;
friend ostream & operator<< {ostream & os,const VintagePort & vp] ;
};
您被指定负责完成VintagePort.
a.第一个任务是重新创建Port方法定义,因为前任被开除时销毁了方法定义。
b.第二个任务是解释为什么有的方法重新定义了,而有些没有重新定义。
c.第三个任务是解释为何没有将operator=( )和opcrator<<( )声明为虚的。
d.第四个任务是提供VintagePort中各个方法的定义。
这是我完善后的答案:
b.有的方法是内联函数,不必重新定义。
c.基类的重载函数和友元函数不能被继承,所以不用声明为虚的。
#include <iostream>
#include <cstring>
using namespace std;
class Port{
private:
char* brand;
char style[20];
int bottles ;
public:
Port (const char* br = "none", const char* st = "none", int b = 0) ;
Port (const Port & p);
virtual ~Port(){ delete [] brand;}
Port& operator = (const Port& pl);
Port& operator += (int b);
Port& operator -= (int b);
int BottleCount() const{ return bottles; }
virtual void Show() const;
friend ostream & operator << (ostream& os, const Port& p) ;
};
Port::Port (const char* br , const char* st , int b): bottles(b){
brand = new char [strlen(br)+1]; //注意要加1!因为字符串在结尾处有一个'\0'用于标记末尾
strcpy (brand, br); //这里不能写brand=br
strcpy (style, st);
}
Port::Port(const Port& p){
brand = new char [strlen (p.brand)+1];//注意sizeof和strlen的区别!!
strcpy (brand, p.brand);
strcpy (style, p.style);
bottles = p.bottles;
}
Port& Port::operator = (const Port& p1){
if(&p1==this) //疑惑:为什么要写成&p1而不是直接p1
return *this;
delete []brand; //把原来的指针delete掉!!
brand = new char [strlen (p1.brand)+1];
strcpy (brand, p1.brand);
strcpy (style, p1.style);
bottles = p1.bottles;
return *this;
}
Port& Port::operator += (int b){
bottles +=b;
return *this;
}
Port& Port::operator -= (int b){
bottles -=b;
return *this;
}
void Port::Show()const{
cout << "Brand:" << brand << endl;
cout << "Kind:" << style << endl;
cout << "Bottles:" << bottles << endl;
}
ostream& operator << (ostream& os, const Port& p){
os << p.brand << ", " << p.style << ", " << p.bottles ;
return os;
}
class VintagePort : public Port {
private:
char* nickname;
int year;
public:
VintagePort() ; //这个一定要记得写
VintagePort (const char* br, int b, const char* nn, int y);
VintagePort (const VintagePort& vp) ;
~VintagePort(){ delete [] nickname; }
VintagePort & operator= (const VintagePort & vp) ;
void Show() const ;
friend ostream & operator<< (ostream & os, const VintagePort & vp) ;
};
VintagePort::VintagePort(): year(0) {
Port("none","vintage",0);
nickname = new char;
nickname = '\0'; //字符串结束标志
}
VintagePort::VintagePort(const char* br, int b, const char* nn, int y): year(y), Port(br, "vintage", b){
nickname = new char [strlen(nn)+ 1];
strcpy (nickname, nn);
}
VintagePort::VintagePort(const VintagePort& vp): Port(vp) //这个太难了,竟然只能写在初始化列表里
{
nickname = new char [strlen(vp.nickname)+ 1];
strcpy (nickname, vp.nickname);
year = vp.year;
}
VintagePort& VintagePort::operator = (const VintagePort &vp){
if(&vp==this)
return *this;
delete []nickname;
nickname = new char [strlen(vp.nickname)+ 1];
strcpy (nickname, vp.nickname);
year = vp.year;
Port::operator =(vp);//难想到!
return *this;
}
void VintagePort::Show() const {
Port::Show();
cout << "Nickname::" << nickname << endl;
cout << "Year:" << year << endl;
}
ostream& operator << (ostream& os, const VintagePort& vp){
os << (const Port&) vp; //有点难!没想到要用强制类型转换,不知道用指针行不行?
os << vp.nickname << "," << vp.year ;
}
int main()
{
Port port1("gallo", "tawny", 20);
cout << port1 << endl << endl;
VintagePort vp("gallo", 24, "Old Velvet", 16);
VintagePort vp2(vp);
cout << vp2 << endl << endl;
VintagePort vp3;
vp3 = vp;
cout << vp3 << endl << endl;
Port * p_port;
p_port = &port1;
p_port->Show();
cout << endl;
p_port = &vp;
p_port->Show();
cout << endl;
return 0;
}