C++包含對(duì)象的類(lèi)(第十四章)

有時(shí)候在類(lèi)中使用別的類(lèi)的組件會(huì)方便很多。這就是has-a關(guān)系。比如學(xué)生類(lèi)中有姓名和一系列考試成績(jī),姓名用string類(lèi)對(duì)象表示,一系列成績(jī)用valarray類(lèi)對(duì)象表示。這就不是is-a關(guān)系了,這是student類(lèi)中has string姓名和valarray成績(jī) 關(guān)系。

valarray類(lèi)簡(jiǎn)單介紹:

使用方法

  1. 聲明方式:
    valarray<int> q_value 尖括號(hào)內(nèi)說(shuō)明這是個(gè)int類(lèi)型模板類(lèi)
  2. 使用對(duì)象:(構(gòu)造函數(shù))
double arr[5] = {3.1,3.5,3.8,3.9,4.0};
valarray<double> v1   一個(gè)size為0的double array
valarray<int> v2(8)   一個(gè)size為8的int array
valarray<int> v3(10,8)  一個(gè)size為8且每個(gè)值初始化為10的int array
valarray<double> v4(arr,4)     一個(gè)size為4,初始值為arr數(shù)組前四個(gè)
valarray<int> v5 = {20,32,1,2}  初始化列表
  1. 使用對(duì)象(基本方法)
    operator[]():訪問(wèn)各個(gè)元素
    size() : 返回包含的元素?cái)?shù)
    sum() : 返回和
    max() , min()

Student類(lèi)對(duì)象設(shè)計(jì)

  1. 關(guān)系has-a的類(lèi),類(lèi)可以獲得實(shí)現(xiàn)但不能繼承接口。而is-a的類(lèi),獲得接口是可以的。
    直觀來(lái)說(shuō):is-a關(guān)系就是派生類(lèi)可以使用基類(lèi)的方法(virtual or not)(純虛函數(shù)只提供接口不提供實(shí)現(xiàn),就是派生類(lèi)需要額外定義才能實(shí)現(xiàn)。接口就是抽象,比如上面的size()就是接口,而size()的功能被實(shí)現(xiàn)就是實(shí)現(xiàn)。)
  2. 比如string+string有意義,但student+student對(duì)象是沒(méi)意義的。但有些借口對(duì)新類(lèi)而言是有意義的,比如string的operator<()用到student類(lèi)對(duì)象可以按姓名順序排序,則可以定義Student::operator<(),然后在內(nèi)部使用string::operator<()
類(lèi)聲明
#ifndef STUDENTC_H_
#define STUDENTC_H_
#include<iostream> 
#include<valarray>
#include<string>
class Student
{
    private:
        typedef std::valarray<double> AR;
        std::string name;
        AR scores;
        std::ostream& arr_out(std::ostream& os) const;
    public:
        Student() : name("No"),scores(){}
        explicit Student(const std::string& s):name(s),scores() {}
        explicit Student(int n): name("Jeff"),scores(n){}
        Student(const std::string& s,int n):name(s),scores(n){}
        Student(const char* str,const double* pd, int n)
        :name(str),scores(pd,n){}
        ~Student(){}
        double average() const;
        const std::string& Name() const;
        double& operator[](int i);
        double operator[](int i) const;
        friend std::istream& operator>>(std::istream& is,Student& s);
        friend std::istream& getline(std::istream& is,Student& s);
        friend std::ostream& operator<<(std::ostream& os,const Student& s);
};
#endif

程序解析:

  1. explicit: 可以用一個(gè)參數(shù)調(diào)用的構(gòu)造函數(shù)用作從參數(shù)類(lèi)型到類(lèi)類(lèi)型的隱式轉(zhuǎn)換函數(shù),但這通常不是好主意,比如int到Student的轉(zhuǎn)換是毫無(wú)意義的,所以用explicit避免隱式轉(zhuǎn)換。
  2. 初始化被包含的對(duì)象:
    用成員初始化列表的方式,如果省略初始化列表,則C++將使用成員對(duì)象(既string和valarray)的默認(rèn)構(gòu)造函數(shù)。而用成員初始化列表name(str)則會(huì)調(diào)用string(const char*)。
  3. private那聲明的函數(shù)也叫輔助函數(shù),輔助函數(shù)可以用在類(lèi)方法中。
源代碼
#include"studentc.h"
using std::cout; 
std::ostream& Student::arr_out(std::ostream& os) const
{
    int i,lim=scores.size();
    if(lim>0)
    {
        for(i=0;i<lim;i++)
        {
            os<<scores[i]<<" ";
            if(i%5==4)
                os<<std::endl;
        }
        if(i%5!=0)
            os<<std::endl;
    }
    else
        os<<"empty scores ";
    return os;
}

double Student::average() const
{
    if(scores.size()!=0)
        return scores.sum()/scores.size();
    else
        return 0; 
}

const std::string& Student::Name() const
{
    return name;
}

double& Student::operator[](int i)
{
    return scores[i];
}

double Student::operator[](int i) const
{
    return scores[i];
}



std::istream& operator>>(std::istream& is,Student& s)
{
    for(int i=0;i<s.scores.size();i++)
        is>>s.scores[i];
    return is;
}

std::istream& getline(std::istream& is,Student& s)
{

    getline(is,s.name);
    return is;
}

std::ostream& operator<<(std::ostream& os,const Student& s)
{
    os<<"Scores for "<<s.name<<": ";
    s.arr_out(os);
    return os;
}

程序解析:

  1. 使用被包含對(duì)象的接口
    比如scores.size(),就是使用了valarray對(duì)象scores的接口size,但不能繼承接口,既不能Student.size()。
  2. ostream& operator<<(ostream& os,const Student& s)
    首先s.name是一個(gè)string對(duì)象,則將調(diào)用函數(shù)
    ostream& operator<<(ostream& os,const string& s),該函數(shù)位于string類(lèi)型中
  3. valarray也想有<<實(shí)現(xiàn),但沒(méi)有這種實(shí)現(xiàn),所以可以定義一個(gè)私有輔助函數(shù),然后在<<函數(shù)中使用輔助函數(shù)來(lái)實(shí)現(xiàn)功能。
主程序
#include"studentc.h"
using namespace std;
void set(Student& s,int n);
const int pupils =3;
const int quizzes = 5;

int main()
{
    Student ada[pupils]={Student(quizzes),Student(quizzes),Student(quizzes)};
    int i;
    for(i=0;i<pupils;i++)
        set(ada[i],quizzes);
    cout<<"\nStudent list:\n";
    for(i=0;i<pupils;i++)
    {
        cout<<ada[i].Name()<<" ";
    }
    cout<<"\nStudent scores:\n";
    for(i=0;i<pupils;i++)
    {
        cout<<ada[i];
        cout<<"Average: "<<ada[i].average()<<endl;
    }
    cout<<"Done";
    return 0;
}

void set(Student& s,int n)
{
    cout<<"Enter the name: ";
    getline(cin,s);
    cout<<"Enter "<<n<<" scores: ";
    for(int i=0;i<n;i++)
        cin>>s[i];
    while(cin.get()!='\n')
        continue;
}

程序解析:

  1. 使用set函數(shù)來(lái)設(shè)置類(lèi)對(duì)象值,在set中調(diào)用成員函數(shù)getline和>>函數(shù)
  2. 使用類(lèi)數(shù)組,數(shù)組大小表示學(xué)生個(gè)數(shù)。
  3. cout<<ada[i].Name()<<" ";將調(diào)用的是string類(lèi)中的<<,不是Student。
    cout<<ada[i]就是調(diào)用Student類(lèi)的<<

關(guān)于類(lèi)對(duì)象的調(diào)用,應(yīng)該比較清楚了


image.png
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

友情鏈接更多精彩內(nèi)容