习题选自:C++ Primer Plus(第六版) 内容仅供参考,如有错误,欢迎指正 ! 第十三章- 类继承学习笔记
派生类继承了基类的公有成员、基类的保护成员和基类的私有成员,但派生类不能直接访问从基类继承过来的私有成员。
派生类不能继承构造函、析构函数、赋值运算符合友元。
如果返回值为void
的,则baseDMA
对象仍可以使用单个赋值,但是不能使用连续赋值。即:
baseDMA magazine("Pandering to Glitz", 1);
baseDMA gift1, gift2, gift3;
gift1 = magazine; //ok
gitft2 = gift3 = gift1; //no 不可用
如果方法返回类型为baseDMA
,则该方法返回的是一个对象,不是引用,导致返回语句的时候需要复制对象,导致该方法执行速度会有所减慢。
按照派生的顺序调用构造函数,最早的构造函数最先调用。调用析构函数的顺序正好相反。
需要,每个类都必须有自己的构造函数,如果派生类没有添加新成员,则构造函数可以为空,但必须存在。
调用派生类方法,它取代基类定义。仅当派生类没有重新定义方法或使用作用域解析运算符时,才会调用基类方法。
如果派生类构造函数使用new或者new[]运算符来初始化类的指针成员,则应定义一个赋值运算符。更普通的说,如果对于派生类成员来说,默认赋值不正确,则应定义赋值运算符。
可以将派生类对象的地址赋给基类指针。但只有通过显示类型转换,才可以将基类对象的地址赋给派生类指针(向下转换),而使用这样的指针不一定安全。
可以将派生类对象的地址赋值给基类对象,对于派生类中新增的数据成员都不会传递给基类对象,程序也将使用基类的赋值运算符。仅当派生类定义了转换运算符(即包含将基类引用作为唯一参数的构造函数)或使用基类为参数的赋值运算符时,相反的赋值才是可能的。
应为c++允许基类引用指向从该基类派生而来的任何类型。
按值传递对象将调用复制构造函数,由于形参是基类对象,因此将调用基类的复制构造函数,复制构造函数已基类引用为参数,该引用可以将指向作为参数传递的派生对象,最终的结构是,将生成一个新的基类对象,其成员对应于派生类对象的基类部分。
按引用传递对象,这样可以确保函数从虚函数受益。另外,按引用传递对象可以节省内存和时间,尤其对于大型对象。按值传递对象的主要有点在于可以保护原始数据,但可以通过将引用作为const类型传递,来达到同样的目的。
a. ph-head()
调用Corporation::head()
;
b. ph-head()
调用PublicCorporation::head()
;
class Kitchen
{
private:
double kit_sq_ft;
public:
Kitchen() { kit_sq_ft = 0.0; }
virtual double area() const { return kit_sq_ft * kit_sq_ft; }
};
class House : public Kitchen
{
private:
double all_sq_ft;
public:
House() { all_sq_ft += kit_sq_ft;}
double area(const char *s) const { cout << s; return all_sq_ft; }
};
首先,这种情况不符合is-a
模型,因此公有继承不适用。其次,House中area()
定义成带参数的,将隐藏area()
的Kitchen
版本。
// 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(char * s1, char * s2, int n, double x);
Cd(const Cd & d);
Cd();
~Cd();
void Report() const; // reports all CD data
Cd & operator=(const Cd & d);
};
#include <iostream>
using namespace std;
#include "classic.h" // which will contain #include cd.h
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: ";
Classic copy;
copy = c2;
copy.Report();
return 0;
}
void Bravo(const Cd & disk)
{
disk.Report();
}
classic.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(char* s1, char* s2, int n, double x);
Cd(const Cd& d);
Cd();
virtual ~Cd();
virtual void Report() const; // reports all CD data
virtual Cd& operator=(const Cd& d);
};
class Classic : public Cd {
private:
char* primary_work;
public:
Classic(char* sc, char* s1, char* s2, int n, double x);
Classic(const Classic& c);
Classic();
virtual ~Classic();
virtual void Report() const;
virtual Classic& operator=(const Classic& c);
};
classic.cpp:
#include "classic.h"
#include <cstring>
#include <iostream>
Cd::Cd(char* s1, char* s2, int n, double x) {
std::strncpy(performers, s1, 50);
std::strncpy(label, s2, 20);
selections = n;
playtime = x;
}
Cd::Cd(const Cd& d) {
std::strncpy(performers, d.performers, 50);
std::strncpy(label, d.label, 20);
selections = d.selections;
playtime = d.playtime;
}
Cd::Cd() {
performers[0] = '\0';
label[0] = '\0';
selections = 0;
playtime = 0;
}
Cd::~Cd() {}
void Cd::Report() const {
std::cout << "Performers: " << performers << std::endl;
std::cout << "Label: " << label << std::endl;
std::cout << "Selections: " << selections << std::endl;
std::cout << "PlayTime: " << playtime << std::endl;
}
Cd& Cd::operator=(const Cd& d) {
if (&d == this) return *this;
std::strncpy(performers, d.performers, 50);
std::strncpy(label, d.label, 20);
selections = d.selections;
playtime = d.playtime;
return *this;
}
Classic::Classic(char* sc, char* s1, char* s2, int n, double x)
: Cd(s1, s2, n, x) {
primary_work = new char[std::strlen(sc) + 1];
std::strcpy(primary_work, sc);
}
Classic::Classic(const Classic& c) : Cd(c) {
primary_work = new char[std::strlen(c.primary_work) + 1];
std::strcpy(primary_work, c.primary_work);
}
Classic::Classic() : Cd() { primary_work = nullptr; }
Classic::~Classic() { delete[] primary_work; }
void Classic::Report() const {
Cd::Report();
std::cout << "PrimaryWork: " << primary_work << std::endl;
}
Classic& Classic::operator=(const Classic& c) {
if (&c == this) return *this;
delete[] primary_work;
Cd::operator=(c);
primary_work = new char[std::strlen(c.primary_work) + 1];
std::strcpy(primary_work, c.primary_work);
return *this;
}
main.cpp:
#include <iostream>
using namespace std;
#include "classic.h" // which will contain #include cd.h
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: ";
Classic copy;
copy = c2;
copy.Report();
return 0;
}
void Bravo(const Cd &disk) { disk.Report(); }
classic.h:
// base class
class Cd { // represents a CD disk
private:
char* performers;
char* label;
int selections; // number of selections
double playtime; // playing time in minutes
public:
Cd(char* s1, char* s2, int n, double x);
Cd(const Cd& d);
Cd();
virtual ~Cd();
virtual void Report() const; // reports all CD data
virtual Cd& operator=(const Cd& d);
};
class Classic : public Cd {
private:
char* primary_work;
public:
Classic(char* sc, char* s1, char* s2, int n, double x);
Classic(const Classic& c);
Classic();
virtual ~Classic();
virtual void Report() const;
virtual Classic& operator=(const Classic& c);
};
classic.cpp:
#include "classic.h"
#include <cstring>
#include <iostream>
Cd::Cd(char* s1, char* s2, int n, double x) {
performers = new char[std::strlen(s1) + 1];
label = new char[std::strlen(s2) + 1];
std::strcpy(performers, s1);
std::strcpy(label, s2);
selections = n;
playtime = x;
}
Cd::Cd(const Cd& d) {
performers = new char[std::strlen(d.performers) + 1];
label = new char[std::strlen(d.label) + 1];
std::strcpy(performers, d.performers);
std::strcpy(label, d.label);
selections = d.selections;
playtime = d.playtime;
}
Cd::Cd() {
performers = nullptr;
label = nullptr;
selections = 0;
playtime = 0;
}
Cd::~Cd() {
delete[] performers;
delete[] label;
}
void Cd::Report() const {
std::cout << "Performers: " << performers << std::endl;
std::cout << "Label: " << label << std::endl;
std::cout << "Selections: " << selections << std::endl;
std::cout << "PlayTime: " << playtime << std::endl;
}
Cd& Cd::operator=(const Cd& d) {
if (&d == this) return *this;
std::strncpy(performers, d.performers, 50);
std::strncpy(label, d.label, 20);
selections = d.selections;
playtime = d.playtime;
return *this;
}
Classic::Classic(char* sc, char* s1, char* s2, int n, double x)
: Cd(s1, s2, n, x) {
primary_work = new char[std::strlen(sc) + 1];
std::strcpy(primary_work, sc);
}
Classic::Classic(const Classic& c) : Cd(c) {
primary_work = new char[std::strlen(c.primary_work) + 1];
std::strcpy(primary_work, c.primary_work);
}
Classic::Classic() : Cd() { primary_work = nullptr; }
Classic::~Classic() { delete[] primary_work; }
void Classic::Report() const {
Cd::Report();
std::cout << "PrimaryWork: " << primary_work << std::endl;
}
Classic& Classic::operator=(const Classic& c) {
if (&c == this) return *this;
delete[] primary_work;
Cd::operator=(c);
primary_work = new char[std::strlen(c.primary_work) + 1];
std::strcpy(primary_work, c.primary_work);
return *this;
}
main.cpp:
#include <iostream>
using namespace std;
#include "classic.h" // which will contain #include cd.h
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: ";
Classic copy;
copy = c2;
copy.Report();
return 0;
}
void Bravo(const Cd &disk) { disk.Report(); }
abc.h:
#ifndef ABC_H_
#define ABC_H_
#include <iostream>
class ABC {
private:
char* label;
int rating;
public:
ABC(const char* l = "null", int r = 1);
ABC(const ABC& a);
virtual ~ABC() = 0;
virtual void View() const;
ABC& operator=(const ABC& a);
friend std::ostream& operator<<(std::ostream& os, const ABC& a);
};
class baseDMA : public ABC {
private:
public:
baseDMA(const char* l = "null", int r = 0);
friend std::ostream& operator<<(std::ostream& os, const baseDMA& rs);
};
class lacksDMA : public ABC {
private:
enum { COL_LEN = 40 };
char color[COL_LEN];
public:
lacksDMA(const char* c = "blank", const char* l = "null", int r = 0);
lacksDMA(const char* c, const ABC& a);
virtual void View() const;
friend std::ostream& operator<<(std::ostream& os, const lacksDMA& rs);
};
class hasDMA : public ABC {
private:
char* style;
public:
hasDMA(const char* s = "none", const char* l = "null", int r = 0);
hasDMA(const char* s, const ABC& c);
hasDMA(const hasDMA& hs);
~hasDMA();
virtual void View() const;
hasDMA& operator=(const hasDMA& rs);
friend std::ostream& operator<<(std::ostream& os, const hasDMA& rs);
};
#endif // ABC_H_
abc.cpp:
#include "abc.h"
#include <cstring>
ABC::ABC(const char* l, int r) {
label = new char(std::strlen(l) + 1);
std::strcpy(label, l);
rating = r;
}
ABC::ABC(const ABC& a) {
label = new char(std::strlen(a.label) + 1);
std::strcpy(label, a.label);
rating = a.rating;
}
ABC::~ABC() { delete[] label; }
void ABC::View() const { std::cout << *this << std::endl; }
ABC& ABC::operator=(const ABC& a) {
if (&a == this) return *this;
delete[] label;
label = new char[std::strlen(a.label) + 1];
std::strcpy(label, a.label);
rating = a.rating;
}
std::ostream& operator<<(std::ostream& os, const ABC& a) {
os << "label: " << a.label << ", rating: " << a.rating;
return os;
}
/***************baseDMA************/
baseDMA::baseDMA(const char* l, int r) : ABC(l, r) {}
std::ostream& operator<<(std::ostream& os, const baseDMA& rs) {
os << (const ABC&)rs;
return os;
}
/***************lacksDMA************/
lacksDMA::lacksDMA(const char* c, const char* l, int r) : ABC(l, r) {
std::strncpy(color, c, COL_LEN);
}
lacksDMA::lacksDMA(const char* c, const ABC& a) : ABC(a) {
std::strncpy(color, c, COL_LEN);
}
void lacksDMA::View() const { std::cout << *this << std::endl; }
std::ostream& operator<<(std::ostream& os, const lacksDMA& rs) {
os << (const ABC&)rs << ", color: " << rs.color;
return os;
}
/***************hasDMA************/
hasDMA::hasDMA(const char* s, const char* l, int r) : ABC(l, r) {
style = new char[std::strlen(s) + 1];
std::strcpy(style, s);
}
hasDMA::hasDMA(const char* s, const ABC& c) : ABC(c) {
style = new char[std::strlen(s) + 1];
std::strcpy(style, s);
}
hasDMA::hasDMA(const hasDMA& hs) : ABC(hs) {
style = new char[std::strlen(hs.style) + 1];
std::strcpy(style, hs.style);
}
hasDMA::~hasDMA() { delete[] style; }
void hasDMA::View() const { std::cout << *this << std::endl; }
hasDMA& hasDMA::operator=(const hasDMA& hs) {
if (this == &hs) return *this;
ABC::operator=(hs);
delete[] style;
style = new char[std::strlen(hs.style) + 1];
std::strcpy(style, hs.style);
return *this;
}
std::ostream& operator<<(std::ostream& os, const hasDMA& rs) {
os << (const ABC&)rs << ", style: " << rs.style;
return os;
}
main.cpp:
#include <iostream>
#include "abc.h"
int main() {
using std::cout;
using std::endl;
baseDMA shirt("Portrabelly", 8);
lacksDMA balloon("red", "Blumpo", 4);
hasDMA map("Mercator", "Buffalo Kyes", 5);
cout << shirt << endl;
cout << balloon << endl;
cout << map << endl;
lacksDMA balloon2(balloon);
hasDMA map2;
map2 = map;
cout << balloon2 << endl;
cout << map2 << endl;
ABC* pts[3];
pts[0] = &shirt;
pts[1] = &balloon;
pts[2] = ↦
for (int i = 0; i < 3; ++i) cout << *pts[i] << endl;
for (int i = 0; i < 3; ++i) pts[i]->View();
return 0;
}
#include <iostream>
using namespace std;
class Port
{
private:
char * brand;
char style[20]; // i.e., tawny, ruby, vintage
int bottles;
public:
Port(const char * br = "none", const char * st = "none", int b = 0);
Port(const Port & p); // copy constructor
virtual ~Port() { delete [] brand; }
Port & operator=(const Port & p);
Port & operator+=(int b); // adds b to bottles
Port & operator-=(int b); // subtracts b from bottles, if available
int BottleCount() const { return bottles; }
virtual void Show() const;
friend ostream & operator<<(ostream & os, const Port & p);
};
Brand: Gallo
Kind: tawny
Bottles: 20
Gallo, tawny, 20
class VintagePort : public Port // style necessarily = "vintage"
{
private:
char * nickname; // i.e., "The Noble" or "Old Velvet", etc.
int year; // vintage 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);
};
port.h:
#ifndef PORT_H_
#define PORT_H_
#include <iostream>
using namespace std;
class Port {
private:
char* brand;
char style[20]; // i.e., tawny, ruby, vintage
int bottles;
public:
Port(const char* br = "none", const char* st = "none", int b = 0);
Port(const Port& p); // copy constructor
virtual ~Port() { delete[] brand; }
Port& operator=(const Port& p);
//派生类的计算逻辑与基类一致,且在该方法中派生类未操作其新增成员,因此该函数在派生类中不需要重新定义
Port& operator+=(int b); // adds b to bottles
//派生类的计算逻辑与基类一致,且在该方法中派生类未操作其新增成员,因此该函数在派生类中不需要重新定义
Port& operator-=(int b); // subtracts b from bottles, if available
int BottleCount() const { return bottles; }
virtual void Show() const;
friend ostream& operator<<(ostream& os, const Port& p);
};
class VintagePort : public Port // style necessarily = "vintage"
{
private:
char* nickname; // i.e., "The Noble" or "Old Velvet", etc.
int year; // vintage 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);//增加了新的成员nickname和year,且赋值运算符不能被继承,需要重新定义
void Show() const;//增加了新的成员nickname和year,需要重新定义
friend ostream& operator<<(ostream& os, const VintagePort& vp);//友元函数不属于成员函数,无法继承
};
#endif // PORT_H_
port.cpp:
#include "port.h"
#include <cstring>
Port::Port(const char* br, const char* st, int b) {
brand = new char[strlen(br) + 1];
strcpy(brand, br);
strncpy(style, st, 20);
bottles = b;
}
Port::Port(const Port& p) {
brand = new char[strlen(p.brand) + 1];
strcpy(brand, p.brand);
strncpy(style, p.style, 20);
bottles = p.bottles;
}
Port& Port::operator=(const Port& p) {
if (&p == this) return *this;
delete[] brand;
brand = new char[strlen(p.brand) + 1];
strcpy(brand, p.brand);
strncpy(style, p.style, 20);
bottles = p.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 << "Style: " << style << endl;
cout << "Bottles: " << bottles << endl;
}
ostream& operator<<(ostream& os, const Port& p) {
os << p.brand << ", " << p.style << ", " << p.bottles;
return os;
}
VintagePort::VintagePort() : Port() {
nickname = new char[strlen("none") + 1];
strcpy(nickname, "none");
year = 0;
}
VintagePort::VintagePort(const char* br, int b, const char* nn, int y)
: Port(br, "Vintage", b) {
nickname = new char[strlen(nn) + 1];
strcpy(nickname, nn);
year = y;
}
VintagePort::VintagePort(const VintagePort& vp) : Port(vp) {
nickname = new char[std::strlen(vp.nickname) + 1];
std::strcpy(nickname, vp.nickname);
year = vp.year;
}
VintagePort& VintagePort::operator=(const VintagePort& vp) {
if (this == &vp) return *this;
Port::operator=(vp);
delete[] nickname;
nickname = new char[std::strlen(vp.nickname) + 1];
std::strcpy(nickname, vp.nickname);
year = vp.year;
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;
return os;
}
main.cpp:
#include <iostream>
#include "port.h"
int main() {
Port p1;
Port p2("Abc", "Bcc", 30);
std::cout << p1 << std::endl;
std::cout << p2 << std::endl;
Port p3 = p2;
p3.Show();
p3 += 3;
p3.Show();
Port p4 = p2;
p3 -= 2;
p3.Show();
VintagePort vp1("Vabc", 50, "hn", 1983);
vp1.Show();
VintagePort vp2;
vp2.Show();
vp1 -= 3;
vp2 = vp1;
std::cout << vp2 << std::endl;
return 0;
}