先附上实例:
1 #pragma once
2 //dma.h -- inheritance and dynamic memory allocation
3 #ifndef DMA_H_
4 #define DMA_H__
5 #include<iostream>
6 #include<cstring>
7 //Base Class Using DMA
8 class baseDMA
9 {
10 private:
11 char *label;
12 int rating;
13 void give_label(const char* b_label) //label的初始化 代码简化
14 {int len = std::strlen(b_label); label = new char[len + 1]; strcpy_s(label, len+1, b_label);}
15 public:
16 baseDMA(const char* b_label = "null", int b_rating = 0);//一般构造函数
17 baseDMA(const baseDMA& rs); //复制构造函数
18 void View() { std::cout << "baseDMA :" << label << std::endl; }//业务函数View
19 virtual void vView() { std::cout << "virtual baseDMA :" << label << std::endl; }//业务虚函数vView
20 virtual ~baseDMA();
21 baseDMA& operator=(const baseDMA& rs); //赋值=运算符
22 friend std::ostream& operator<<(std::ostream& os, const baseDMA& rs);
23 };
24
25 //derived class without DMA
26 //no destructor needed
27 //uses implicit copy constructor
28 //uses implicit assignment operator
29 class lacksDMA :public baseDMA
30 {
31 private:
32 enum { COLOR_LEN = 40 };
33 char color[COLOR_LEN];
34 public:
35 lacksDMA(const char* l_color = "blank", const char* l_label = "null", int l_rating = 0);//一般构造函数
36 lacksDMA(const char* l_color, const baseDMA& rs); //基类构造函数
37 void View(){ std::cout << "lacksDMA :" << color << std::endl; }//业务函数View
38 virtual void vView() { std::cout << "virtual lacksDMA :" << color << std::endl; }//业务虚函数vView
39 friend std::ostream& operator<<(std::ostream& os, const lacksDMA& rs);
40 };
41 //derived class with DMA
42 class hasDMA :public baseDMA
43 {
44 private:
45 char* style;
46 void give_style(const char* h_style) //style的初始化 代码简化
47 {int len = std::strlen(h_style); style = new char[len + 1]; strcpy_s(style, len+1, h_style);}
48 public:
49 hasDMA(const char* h_style = "none", const char* h_lable = "null", int h_rating = 0);//一般构造函数
50 hasDMA(const char* s, const baseDMA& rs); //基类构造函数
51 hasDMA(const hasDMA& hs); //复制构造函数
52 void View() { std::cout << "hasDMA :" << this->style << std::endl; }//业务函数View
53 virtual void vView() { std::cout << "virtual hasDMA :" << style << std::endl; }//业务虚函数vView
54 ~hasDMA();
55 hasDMA&operator=(const hasDMA& rs); //赋值=运算符
56 friend std::ostream& operator<<(std::ostream &os, const hasDMA& rs);
57 };
58 #endif // !DMA_H_
dma.h
1 //dma.cpp -- dma class methods
2 #include "dma.h"
3
4
5 //baseDMA methods
6 baseDMA::baseDMA(const char* b_label, int b_rating) //一般构造函数
7 {
8 give_label(b_label);
9 /* int len = strlen(b_lable) + 1;
10 label = new char[len];
11 strcpy_s(label,len, b_lable); */
12 rating = b_rating;
13 }
14 baseDMA::baseDMA(const baseDMA& rs) //复制构造函数
15 {
16 give_label(rs.label);
17 /* int len = strlen(b_lable) + 1;
18 label = new char[len];
19 strcpy_s(label,len, b_lable); */
20 rating = rs.rating;
21 }
22 baseDMA::~baseDMA() { delete[] label; }
23 baseDMA& baseDMA::operator=(const baseDMA& rs) //赋值运算符
24 {
25 if (this == &rs)
26 return *this;
27 delete[]label;
28 give_label(rs.label);
29 /* int len = strlen(rs.label) + 1;
30 label = new char[len];
31 strcpy_s(label, len, rs.label); */
32 rating = rs.rating;
33 return *this;
34 }
35 std::ostream& operator<<(std::ostream& os, const baseDMA& rs)
36 {
37 os << "Label:" << rs.label << std::endl;
38 os << "Rating: " << rs.rating << std::endl;
39 return os;
40 }
41
42 //lacksDMA methods //一般构造函数
43 lacksDMA::lacksDMA(const char* l_color, const char* l_label, int l_rating) :baseDMA(l_label, l_rating)
44 {
45 strncpy_s(color, l_color, 39);
46 color[39] = '\0';
47 }
48 lacksDMA::lacksDMA(const char* c, const baseDMA& rs) : baseDMA(rs) //基类构造函数
49 {
50 strncpy_s(color, c, COLOR_LEN - 1);
51 color[COLOR_LEN - 1] = '\0';
52 }
53 std::ostream& operator<<(std::ostream& os,const lacksDMA& ls)
54 {
55 os << (const baseDMA&)ls;
56 os << "Color: " << ls.color << std::endl;
57 return os;
58 }
59 //void lacksDMA::View() { const baseDMA& bs = *this; std::cout << "lacksDMA :" << bs.label; }
60 //hasDMA methods
61 hasDMA::hasDMA(const char* h_style, const char* h_label, int h_rating) :baseDMA(h_label, h_rating)
62 { //一般构造函数
63 give_style(h_style);
64 /* int len = strlen(h_style) + 1;
65 style = new char[len];
66 strcpy_s(style, len, h_style ); */
67 }
68 hasDMA::hasDMA(const char* h_style, const baseDMA& rs) : baseDMA(rs) //基类构造函数
69 {
70 give_style(h_style);
71 /* int len = strlen(h_style) + 1;
72 style = new char[len];
73 strcpy_s(style, len, h_style ); */
74 }
75 hasDMA::hasDMA(const hasDMA& hs):baseDMA(hs) //复制构造函数
76 {
77 give_style(hs.style);
78 /* int len = strlen(h_style) + 1;
79 style = new char[len];
80 strcpy_s(style, len, h_style ); */
81 }
82 hasDMA::~hasDMA() { delete[] style; }
83 hasDMA&hasDMA::operator=(const hasDMA& hs) //赋值运算符
84 {
85 if (this == &hs)
86 return *this;
87 baseDMA::operator=(hs);
88 delete[]style;
89 give_style(hs.style);
90 /* int len = strlen(h_style) + 1;
91 style = new char[len];
92 strcpy_s(style, len, h_style ); */
93 return *this;
94 }
95 std::ostream&operator<<(std::ostream &os, const hasDMA&hs)
96 {
97 os << (const baseDMA&)hs;
98 os << "Style: " << hs.style << std::endl;
99 return os;
100 }
dma.cpp
dma-mamin.cpp
1 #pragma once
2 //studentc.h -- defining aStudent class using containment
3 #ifndef STUDENTC_H_
4 #define STUDENTC_H_
5
6 #include<iostream>
7 #include<string>
8 #include<valarray>
9 class Student
10 {
11 private:
12 typedef std::valarray<double>ArrayDb;
13 std::string name;
14 ArrayDb scores;
15 //prevate method for scores output
16 std::ostream& arr_out(std::ostream& os)const;
17 public:
18 Student():name("Null Student"),scores(){}
19 explicit Student(const std::string &s):name(s),scores(){}
20 explicit Student(int n):name("Nully"),scores(n){}
21 Student(const std::string&s,int n):name(s),scores(n){}
22 Student(const std::string&s,const ArrayDb& a):name(s),scores(a){}
23 Student(const char*str, const double*pd, int n) :name(str), scores(pd, n){}
24 ~Student(){}
25
26 double Average()const; //get average scores
27 const std::string& Name()const; //get name
28 double&operator[](int i); //get scores[i]
29 double operator[](int i)const;
30 //friend input1 a word,2 a line; output
31 friend std::istream& operator>>(std::istream &is, Student &stu); //cin>>name
32 friend std::istream& getline(std::istream&is, Student& stu); //cout<<name
33 friend std::ostream& operator<<(std::ostream&os,const Student &stu); //cout<<name and arr_out()scores
34 };
35 #endif // ! STUDENTC_H_
36 /* valarray类简介
37 函数构造例子
38 valarray<double> v1;//an array of double,size 0
39 valarray<int> v2(8); //an array of 8 int elements
40 valarray<int> v2(8); //an array of 8 int elements, each set 10
41 double gps[5]={1,2,3,4,5};
42 valarray<double> v2(gps,4); //an array of 4 elements,initalized to the first 4 elements of gps
43 valarray<int> v={6,7,8,9,10,11};
44 方法:
45 operator[]() size() sum() max() min()
46 */
studnetc.h
1 //studentc.cpp -- Student class using containment
2 #include "studentc.h"
3 using std::ostream;
4 using std::istream;
5 using std::endl;
6 using std::string;
7 //public methods
8 double Student::Average()const
9 {
10 if (scores.size() > 0)
11 return scores.sum() / scores.size();
12 else
13 return 0;
14 }
15 const string& Student::Name()const { return name; }
16 //use valarray<double>::operator[]()
17 double& Student::operator[](int i) { return scores[i]; }
18 double Student::operator[](int i)const { return scores[i]; }
19 //private method
20 ostream& Student::arr_out(ostream& os)const
21 {
22 int i; int lim = scores.size();
23 if (lim > 0)
24 {
25 for ( i= 0; i < lim; i++)
26 {
27 os << scores[i] << " ";
28 if (i % 5 == 4) os << endl;
29 }
30 if (i % 5 != 0) os << endl;
31 }
32 else
33 os << " empty array ";
34 return os;
35 }
36 //friends
37 //use string version of operator>>()
38 istream& operator>>(istream& is, Student& stu)
39 {
40 is >> stu.name;
41 return is;
42 }
43 istream&getline(istream& is, Student &stu)
44 {
45 getline(is, stu.name);
46 return is;
47 }
48 ostream& operator<<(ostream& os,const Student& stu)
49 {
50 os << "Scores for "<<stu.name<<":\n";
51 stu.arr_out(os);
52 return os;
53 }
studentc.cpp
1 //use_stuc.cpp -- using acomposite class
2 //copile with studentc.cpp
3 #include<iostream>
4 #include "studentc.h"
5 using std::cin;
6 using std::cout;
7 using std::endl;
8 //void set(Student&sa, int n);
9 const int NStudent = 3;
10 const int NScoure = 5;
11 int main()
12 {
13
14 return 0;
15 }
16 /*
17 Student ada[NStudent] = { Student(NScoure),Student(NScoure),Student(NScoure) };
18 int i;
19 for (i = 0; i < NStudent; ++i)
20 set(ada[i], NScoure);
21
22 cout << "\nStudent List:\n";
23 for (i = 0; i < NStudent; ++i)
24 cout << ada[i].Name() << endl;
25
26 cout << "\nResults:";
27 for (i = 0; i < NStudent; ++i)
28 {
29 cout << endl << ada[i];
30 cout << "average: " << ada[i].Average() << endl;
31 }
32 cout << "Done.\n";
33 cin.get();
34
35 void set(Student& sa, int n)
36 {
37 cout << "Please enter the student's name: ";
38 getline(cin, sa);
39 cout << "Please enter " << n << " quiz scores:\n";
40 for (int i = 0; i < n; i++)
41 cin >> sa[i];
42 while (cin.get() != '\n')
43 continue;
44 } */
studentc-main
类的继承格式: class lacksDMA :public baseDMA是基类,lacksDMA是派生类,public表示公有继承;如果有多个继承类需要用逗号隔开,
:public baseDMA,public std::string{};默认私有继承。
一、基类与派生类
数据关系:使用公有派生,基类的公有成员将成为派生类的公有成员,基类的私有部分将成为派生类的一部分,但只能通过基类的公有和保护方法访问。
隐式向上转换 意味着无需进行显示类型转换,就可以将基类指针或引用指向派生类对象。
各种继承方式
特征 | 公有继承 | 保护继承 | 私有继承 |
公有成员变成 | 派生类公有成员 | 派生类的保护成员 | 派生类的私有成员 |
保护成员变成 | 派生类的保护成员 | 派生类的保护成员 | 派生类的私有成员 |
私有成员变成 | 只能通过基类接口访问 | 只能通过基类接口访问 | 只能通过基类接口访问 |
能否隐式向上转换 | 是 | 是(但只能在派生类中) | 否 |
类型转换:只有派生类能转换为基类,但即使转换为基类也不能调用基类的私有成员,因为私有成员的作用域不在派生类中,基类公有成员则能。
类型关系:①is-a,即派生类is-a-kind-of基类,派生类只是基类数据与接口成员的扩充 如苹果(名称,颜色)-水果(热量,重量);
ABC,如从矩形Ellipse和Circle类中,抽象出它们的共性,将这些特性放到一个ABC中,然后从ABC中派生出Circle和Ellipse类。(见dma代码)
③has-a,方式1私有继承,:private std::string,private std::valarray<int>{};方式2包含,{private:std::string str1;……};(见studentc代码)
has-a利用他人开发好的string 为动态内存分配省去了大量支持代码,方式1不能是公有继承,因为那样会使Student继承string的+接口,
而两个Student类型相加是无意义的。
建议使用③的包含方式,方式2比1强在string可以声明多个数据名称,而且可以直接对string数据操作。
二、重要函数
基类构造函数: 1. hasDMA::hasDMA(const char* h_style, const
2. explicit Student(const std::string
eg1 :hasDMA是baseDMA的派生类,参数rs将转换为baseDMA变量去初始化 hasDMA对象的基类数据部分;参数s初始化数据name。
参数 初始化列表格式: ①基类名(能转换为基类的参数变量) ②类数据名称(参数变量) 如name(s)。多个参数参数用逗号隔开。
无参 其中score()调用valarray<double>()会默认构造函数,也可以有baseDMA();
注意,关键字explicit可防止 stu="hello world";这样的隐式转换。
基类与派生类可以定义相同名称的函数。类对象(或该类引用、指针形式)将调用对应类的方法;(baseDMA)has1,(baseDMA&)has1,(baseDMA*)has1将调用基类方法。
虚函数格式:函数声明前加上关键字virtual。(虚函数可以不必实现)
对象(或该类引用、指针形式)将调用对应类的方法。(baseDMA)has1调用基类虚方法,(baseDMA&)has1,(baseDMA*)has1将调用派生类虚方法。eg:dmp-main.cpp
1 hasDMA has1("blue", "has_rank", 5);
2 baseDMA* has2 = &has1; baseDMA& has3 = has1;
3 cout << "has1实函数 :\nhas1、 (baseDMA*)has1、 (baseDMA&)has1\n";
4 has1.View(); has2->View(); has3.View();
5 cout << "\nhas1虚函数virtual :\nhas1、 (baseDMA*)has1、 (baseDMA&)has1\n";
6 has1.vView(); has2->vView(); has3.vView();
7 cout << "\n\n";
View Code
测试结果:
三、继承和动态内存分配
1.派生类不使用new 如dmp中lackDMA类不需要定义析构函数、复制构造函数和赋值运算符。基类构造函数还是要的。
2.派生类使用new 如dmp中hasDMA类需要使用这三个函数。
派生类的基类数据部分:一般构造函数和基类构造函数,复制构造函数和赋值运算符也需要重写。
所以基类(如果也使用了new)有3部分代码重复,派生类有4部分代码重复。
①class baseDMA{
private:
char* label;
int rating;
void give_label(const char* b_label,int b_rating) //label的初始化 代码简化
{ int len = std::strlen(b_label); label = new char[len + 1]; strcpy_s(label, len + 1, b_label); rating = b_rating; }
1、baseDMA::baseDMA(const char* b_label, int b_rating) //一般构造函数
{ give_label(b_label,b_rating);}
2、baseDMA::baseDMA(const baseDMA& rs) //复制构造函数
{ give_label(rs.label,rs.rating); }
3、baseDMA& baseDMA::operator=(const baseDMA& rs) //赋值运算符
{ if (this == &rs)
return *this; delete[]label; give_label(rs.label,rs.rating); return *this; }
②class hasDMA :public baseDMA{
private:
char* style;
void give_style(const char* h_style) //style的初始化 代码简化
{int len = std::strlen(h_style); style = new char[len + 1]; strcpy_s(style, len+1, h_style);}
1、hasDMA::hasDMA(const char* h_style, const char* h_label, int h_rating) :baseDMA(h_label, h_rating) //一般构造函数 参数列表-基类部分
{ give_style(h_style); }
2、hasDMA::hasDMA(const char* h_style, const baseDMA& rs) : baseDMA(rs) //基类构造函数 参数列表-基类部分
{ give_style(h_style);}
3、hasDMA::hasDMA(const hasDMA& hs):baseDMA(hs) //复制构造函数 参数列表-基类部分
{ give_style(hs.style);}
4、hasDMA::~hasDMA() { delete[] style; }
hasDMA& hasDMA::operator=(const hasDMA& hs) //赋值运算符 调用处理-基类部分eg,baseDMA::operator=(hs)
{
if (this == &hs)
return *this; baseDMA::operator=(hs); //调用处理基类部分
delete[]style; give_style(hs.style); return *this; }
基类友元函数不是成员函数,派生类不能直接调用,但在可以强制转换为基类调用eg: os << (const
os<<hs操作须保证hs为const类型, 而(const hasDMA)类型只能调用const函数如 void View()const{};