有時(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)單介紹:
使用方法
- 聲明方式:
valarray<int> q_value尖括號(hào)內(nèi)說(shuō)明這是個(gè)int類(lèi)型模板類(lèi)- 使用對(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} 初始化列表
- 使用對(duì)象(基本方法)
operator[]():訪問(wèn)各個(gè)元素
size() : 返回包含的元素?cái)?shù)
sum() : 返回和
max() , min()
Student類(lèi)對(duì)象設(shè)計(jì)
- 關(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)。)- 比如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
程序解析:
- 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)換。
- 初始化被包含的對(duì)象:
用成員初始化列表的方式,如果省略初始化列表,則C++將使用成員對(duì)象(既string和valarray)的默認(rèn)構(gòu)造函數(shù)。而用成員初始化列表name(str)則會(huì)調(diào)用string(const char*)。- 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;
}
程序解析:
- 使用被包含對(duì)象的接口
比如scores.size(),就是使用了valarray對(duì)象scores的接口size,但不能繼承接口,既不能Student.size()。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)型中- 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;
}
程序解析:
- 使用set函數(shù)來(lái)設(shè)置類(lèi)對(duì)象值,在set中調(diào)用成員函數(shù)getline和>>函數(shù)
- 使用類(lèi)數(shù)組,數(shù)組大小表示學(xué)生個(gè)數(shù)。
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