• valarray 包含对象成员的类(cpp14章)


    C++代码重用   

    1.公有继承可以实现 

    2.包含、私有继承、保护继承用于实现has-a关系,即新的类将包含另一个类的对象

    (使用这样类成员:本身是另外一个类对象称为包含 (组合或层次化)。)

    3.函数模板类模板

    valarray类构造函数举例 

    1. double gap[5] = { 3.1,3.5,3.8,2.9,3.3 };
    2. valarray<double> v1; //创建1个double类型的空数组
    3. valarray<int> v2(8); //创建8个int类型数组
    4. valarray<int> v3(10,8); //创建8个int类型数组,数组中每个数都是10
    5. valarray<double> v4(gap,4);//取出gap数组的前四个元素用于填充v4数组
    6. valarray<int> v5 = { 20,32,17,9 };//C++ 11中

    类方法举例:

    1. operator[]() : 访问各个元素
    2. size() : 返回包含的元素数
    3. sum() : 返回所有元素的总和
    4. max() : 返回最大的元素
    5. min(): 返回最小的元素

    举例:每个学生的录入考试成绩  (has_a关系,学生有姓名,也有一组考试成绩)

            Valarray类 包含了string类和valarray

           用string对象表示学生的名字,valarray表示考试的分数

           将其声明为私有,意味着Valarray类的成员函数可以使用string和valarray类的公有接口来访问和修改name和scores对象。但类外不可这么做,只能通过Valarray类的公有接口访问name和scores。通常被描述为:Valarray类获得了其成员对象的实现,但没有继承接口。

    1.代码:(用包含的方法)

    valarray.h

    1. #ifndef VALARRAY_H_
    2. #define VALARRAY_H_
    3. #include
    4. #include
    5. #include
    6. using namespace std;
    7. //14章 14.1 valarray包含成员对象的类
    8. class Student
    9. {
    10. private:
    11. typedef valarray<double> ArrayDb;
    12. string name;
    13. ArrayDb scores;//valarray ArrayDb
    14. public:
    15. Student():name("Null student"),scores(){} //成员初始化列表
    16. explicit Student(const string&s):name(s), scores() {} //explicit关闭隐式转换,使其只能显调用
    17. explicit Student(int n) :name("Nully"), scores(n) {}
    18. Student(const string&s,int n) :name(s), scores(n) {}
    19. Student(const string&s, const ArrayDb &a) :name(s), scores(a) {}
    20. Student(const string&s, const double *pd,int n) :name(s), scores(pd,n) {}
    21. ~Student(){}
    22. double Average() const; //平均成绩 不可修改
    23. const string &Name() const;
    24. double &operator[](int n); //stu[0]=100;
    25. double operator[](int n) const;//a=stu[0]
    26. friend istream &operator >>(istream &is, Student &stu);//友元函数重载输入输出运算符
    27. friend istream &getline(istream &is, Student &stu);
    28. friend ostream &operator<<(ostream &os, Student &stu);
    29. };
    30. #endif // !VALARRAY_H_

    valarray.cpp

    1. #include "valarray.h"
    2. double Student::Average() const
    3. {
    4. if (scores.size() > 0)
    5. return scores.sum() / scores.size();
    6. else
    7. return 0.0;
    8. }
    9. const string & Student::Name() const
    10. {
    11. return name;
    12. }
    13. double & Student::operator[](int n)
    14. {
    15. return scores[n];
    16. }
    17. double Student::operator[](int n) const
    18. {
    19. return scores[n];
    20. }
    21. istream & operator>>(istream & is, Student & stu)
    22. {
    23. is >> stu.name;
    24. return is;
    25. }
    26. istream & getline(istream & is, Student & stu)
    27. {
    28. getline(is, stu.name);
    29. return is;
    30. }
    31. ostream & operator<<(ostream & os, Student & stu)
    32. {
    33. os << "Scores for" << stu.name << ":" << endl;//显示学生的姓名和各科分数
    34. int i;
    35. int lim = stu.scores.size();
    36. if (lim > 0)
    37. {
    38. for ( i = 0; i < lim; i++)
    39. {
    40. os << stu.scores[i] << " ";
    41. if (i % 5 == 4)
    42. os << endl;
    43. }
    44. if (i % 5 != 0)
    45. os << endl;
    46. }
    47. else
    48. os << "Empty array" << endl;
    49. return os;
    50. }

    main.cpp

    1. #include
    2. #include "valarray.h"
    3. using namespace std;
    4. const int pupils = 3; //人数
    5. const int quizzes = 5;//每个人都有5门成绩
    6. void set(Student &sa, int n);
    7. int main()
    8. {
    9. Student ada[pupils] = { Student(quizzes),Student(quizzes) ,Student(quizzes) };
    10. int i;
    11. for (i = 0; i < pupils; i++)
    12. set(ada[i], quizzes);
    13. cout << "\n Student List:" << endl;
    14. for (i = 0; i < pupils; i++)
    15. cout << ada[i].Name() << endl;//显示每个学生的姓名
    16. cout << "\n Result List:" << endl;
    17. for (i = 0; i < pupils; i++)
    18. cout << ada[i];
    19. cout << "Average:" << ada[i].Average() << endl;
    20. return 0;
    21. }
    22. void set(Student &sa, int n)
    23. {
    24. cout << "Please enter the student's name:";
    25. getline(cin, sa);
    26. cout << "Please enter:" << n << "quiz scores:" << endl;
    27. for (int i = 0; i < n; i++)
    28. cin >> sa[i];
    29. while (cin.get() != '\n');
    30. }

    运行结果:

    2.利用私有继承的方法

    使用私有继承,基类的公有方法将成为派生类的私有方法。

    包含和私有继承的不同

    1.包含提供了2个被显示命名的对象成员(name和scores),而私有继承提供了2个无名的子对象成员。

    2.私有继承的构造函数使用初始化成员列表语法,它使用类名而不是成员名来标识构造函数。

    包含:使用成员名name和scores

    Student(const string&s, const double *pd,int n) :name(s), scores(pd,n) {}

    私有继承:使用string和ArrayDb

    Student(const string&s, const double *pd,int n) :string(s), ArrayDb(pd,n) {}

    修改包含代码使其变为私有继承的方式:
    1.访问基类的方法

    包含:使用valarray的 方法,如size()和sum(),使用对象名调用方法

    1. double Student::Average() const
    2. {
    3. if (scores.size() > 0)
    4. return scores.sum() / scores.size();
    5. else
    6. return 0.0;
    7. }

    私有继承(只能在派生类的方法中使用基类的方法):使用类名和作用域与作用域运算符来调用基类的方法

    1. double Student::Average() const
    2. {
    3. if (ArrayDb::size() > 0) //访问基类的方法 使用类名+作用域解析运算符
    4. return ArrayDb::sum() / ArrayDb::size();
    5. else
    6. return 0.0;
    7. }

    2.访问基类对象

    包含:name为string类对象

    1. const string & Student::Name() const
    2. {
    3. return name;
    4. }

    私有继承:string对象没有名称。Student类的代码如何访问string对象?使用强制类型转换

    1. const string & Student::Name() const
    2. {
    3. return (const string &)*this; //访问基类对象 通过强制类型转换
    4. }

    *this为调用方法的对象。返回一个引用,该引用指向用于该方法的Student对象中的继承而来的string对象。

    3.访问基类的友元函数

    类名显示限定函数名不适用于友元函数,因为友元函数不是成员函数,不属于类

    包含:

    1. ostream & operator<<(ostream & os, Student & stu)
    2. {
    3. os << "Scores for" << stu.name << ":" << endl;//显示学生的姓名和各科分数
    4. ....
    5. }

    私有继承:使用显示转换  为基类调用正确的函数

    1. ostream & operator<<(ostream & os, const Student & stu)
    2. {
    3. os << "Scores for" << (string &)stu << ":" << endl;//显示学生的姓名和各科分数
    4. .....
    5. }

    整体代码:

    valarray.h

    1. #ifndef VALARRAY_H_
    2. #define VALARRAY_H_
    3. #include
    4. #include
    5. #include
    6. using namespace std;
    7. //14章 14.2私有继承
    8. class Student:private string,private valarray<double> //私有继承
    9. {
    10. private:
    11. typedef valarray<double> ArrayDb;
    12. // string name;
    13. // ArrayDb scores;//valarray ArrayDb
    14. public:
    15. Student():string("Null student"), ArrayDb(){} //成员初始化列表
    16. explicit Student(const string&s):string(s), ArrayDb() {}
    17. explicit Student(int n) :string("Nully"), ArrayDb(n) {}
    18. Student(const string&s,int n) :string(s), ArrayDb(n) {}
    19. Student(const string&s, const ArrayDb &a) :string(s), ArrayDb(a) {}
    20. Student(const string&s, const double *pd,int n) :string(s), ArrayDb(pd,n) {}
    21. ~Student(){}
    22. double Average() const; //平均成绩 不可修改
    23. const string &Name() const;
    24. double &operator[](int n); //stu[0]=100;
    25. double operator[](int n) const;//a=stu[0]
    26. friend istream &operator >>(istream &is, Student &stu);
    27. friend istream &getline(istream &is, Student &stu);
    28. friend ostream &operator<<(ostream &os,const Student &stu);
    29. };
    30. #endif // !VALARRAY_H_

    valarray.cpp

    1. #include "valarray.h"
    2. double Student::Average() const
    3. {
    4. if (ArrayDb::size() > 0) //访问基类的方法 使用类名+作用域解析运算符
    5. return ArrayDb::sum() / ArrayDb::size();
    6. else
    7. return 0.0;
    8. }
    9. const string & Student::Name() const
    10. {
    11. return (const string &)*this; //访问基类对象 通过强制类型转换
    12. }
    13. double & Student::operator[](int n)
    14. {
    15. return ArrayDb::operator[](n);
    16. }
    17. double Student::operator[](int n) const
    18. {
    19. return ArrayDb::operator[](n); //访问基类的方法 使用类名+作用域解析运算符
    20. }
    21. istream & operator>>(istream & is, Student & stu)
    22. {
    23. is >> (string &)stu;
    24. return is;
    25. }
    26. istream & getline(istream & is, Student & stu)
    27. {
    28. getline(is, (string &)stu);
    29. return is;
    30. }
    31. ostream & operator<<(ostream & os, const Student & stu)
    32. {
    33. os << "Scores for" << (string &)stu << ":" << endl;//显示学生的姓名和各科分数
    34. int i;
    35. int lim = stu.ArrayDb::size();
    36. if (lim > 0)
    37. {
    38. for ( i = 0; i < lim; i++)
    39. {
    40. os << stu.ArrayDb::operator[](i) << " ";
    41. if (i % 5 == 4)
    42. os << endl;
    43. }
    44. if (i % 5 != 0)
    45. os << endl;
    46. }
    47. else
    48. os << "Empty array" << endl;
    49. return os;
    50. }

    main.cpp

    1. #include
    2. #include "valarray.h"
    3. using namespace std;
    4. const int pupils = 3; //人数
    5. const int quizzes = 5;//每个人都有5门成绩
    6. void set(Student &sa, int n);
    7. int main()
    8. {
    9. Student ada[pupils] = { Student(quizzes),Student(quizzes) ,Student(quizzes) };
    10. int i;
    11. for (i = 0; i < pupils; i++)
    12. set(ada[i], quizzes);
    13. cout << "\n Student List:" << endl;
    14. for (i = 0; i < pupils; i++)
    15. cout << ada[i].Name() << endl;//显示每个学生的姓名
    16. cout << "\n Result List:" << endl;
    17. for (i = 0; i < pupils; i++)
    18. cout << ada[i];
    19. cout << "Average:" << ada[i].Average() << endl;
    20. return 0;
    21. }
    22. void set(Student &sa, int n)
    23. {
    24. cout << "Please enter the student's name:";
    25. getline(cin, sa);
    26. cout << "Please enter:" << n << "quiz scores:" << endl;
    27. for (int i = 0; i < n; i++)
    28. cin >> sa[i];
    29. while (cin.get() != '\n');
    30. }

    结果:

    3.使用私有继承的场景:

    1.假设类包含保护成员(可以是数据成员也可以是成员函数),则这样的成员在派生类中是可用的,但在继承层次外是不可用的。使用组合将这样的类包含在另一个类中,则后者将不是派生类,而是继承层次之外,因此不能访问保护成员。  但是通过私有继承得到的将是派生类,因此能够访问保护成员。

    2.当需要重新定义虚函数。派生类可以重新定义虚函数,但包含不可以,使用私有继承,重新定义的函数将只能在类中使用,而不是公有的。

    通常:应使用包含来建立has-a关系;如果新类需要访问原有类的保护成员,或需要重定义一个虚函数,则使用私有继承。

  • 相关阅读:
    【C++】AVL树(动图详解)
    Linux环境配置安装Redis
    Leetcode 第320场周赛
    Java语言中的泛型的概念和使用方法
    < 今日份知识点:浅述对 “ Vue 插槽 (slot) ” 的理解 以及 插槽的应用场景 >
    【数据仓库-零】数据仓库知识体系 ing
    NVIDIA的jetson平台进行can通讯学习,最终实现can收发详细教程(精五)
    上周热点回顾(5.23-5.29)
    pytorch深度学习实战lesson22
    go中并发之waitgroup、runtime、sync、time
  • 原文地址:https://blog.csdn.net/m0_75179090/article/details/133827279