《C++Primer PLus 第五版》读书笔记3(三)

2014-11-24 10:39:59 · 作者: · 浏览: 6
{
if ( ArrayDb::size() > 0 )
{
return ( ArrayDb::sum() / ArrayDb::size() );
}
else
{
return 0;
}
}
const string& GetName() const
{
return ( const string& ) *this;
}
double& operator[] ( int i )
{
return ArrayDb::operator[]( i );
}
const double operator[] ( int i ) const
{
return ArrayDb::operator[]( i );
}
ostream& arr_out( ostream& os ) const
{
int i;
int lim = ArrayDb::size();
if ( lim > 0 )
{
for ( i = 0; i < lim; i++ )
{
// os << ArrayDb[ i ] << " ";
os << ArrayDb::operator[]( i ) << " ";
if ( 4 == i % 5 )
{
os << endl;
}
}
if ( 0 != i % 5 )
{
os << endl;
}
}
else
{
os << "empty array";
}
return os;
}
friend istream& operator >>( istream& is, CStudent& stu );
friend istream& operator <<( istream& os, const CStudent& stu );
friend istream& getline( istream& is, CStudent& stu );
};

istream& operator >>( istream& is, CStudent& stu )
{
is >> ( string& )stu;
return is;
}

ostream& operator <<( ostream& os, const CStudent& stu )
{
os << "this student name is:" << stu.GetName() << endl;
os << "this student scores is:" << endl;
stu.arr_out( os );
return os;
}
istream& getline( istream& is, CStudent& stu )
{
getline( is, ( string& )stu );
return is;
}

const int puplis = 3;
const int quizzes = 5;
void set( CStudent& sa, int n );

int _tmain(int argc, _TCHAR* argv[])
{
CStudent ada[ puplis ] = { CStudent( quizzes ), CStudent( quizzes ), CStudent( quizzes ) };
int i;
for ( i = 0; i < puplis; ++i )
{
set( ada[ i ], quizzes );
}
cout << "\nStudent List:" << endl;
for ( i = 0; i < puplis; ++i )
{
cout << ada[ i ].GetName() << endl;
}
cout << "\nResults:" << endl;
for ( i = 0; i < puplis; i++ )
{
cout << endl << ada[ i ];
cout << "average" << ada[ i ].Average() << endl;
}
cout << "Done." << endl;

return 0;
}

void set( CStudent& sa, int n )
{
cout << "Please enter the student name:";
getline( cin, sa );
cout << "Please enter " << n << "quiz scores:" << endl;
for ( int i = 0; i < n; i++ )
{
cin >> sa[ i ];
}
while( '\n' != cin.get() )
{
continue; }
}

在CStudent类中,使用作用域解析操作符可以访问基类的方法,但要使用基类对象本身,比如调用GetName()方法,他返回string对象成员name,但使用私有继承时,该string对象没有名称,只能使用强制类型转换。由于CStudent类是从string派生出来的,因此可以用过强制类型转换,将CStudent对象转换为string对象,结果为继承而来的string对象。
[cpp]
const string& GetName() const
{
return ( const string& ) *this;
}

引用stu不会自动转换为string引用,根本原因在于,在私有继承中,不在进行显示类型转换的清华下,不能讲指向派生类的引用或指针赋给基类引用或指针。不过,即使这个例子使用的是公有继承,也必须使用显示类型转换。原因之一是,如果不适用类型转换,代码is >>stu;与友元函数原型匹配,从而导致递归调用:
[cpp]
istream& operator >>( istream& is, CStudent& stu )
{
is >> ( string& )stu;
return is;
}


另一个原因是,由于这个类使用的是多重继承,编译器将无法确定应转换成哪个基类,如果两个基类都提供了函数operator<<()。

使用包含还是私有继承
由于既可以使用包含,也可以使用私有继承来建立has-a关系。大多数c++程序员倾向于前者。不过私有继承所提供的特性确实比包含多。例如,假设类包含保护成员,则这样的成员在派生类中式可用的,但在继承层次机构外是不可用的。如果使用组合奖这样的类保护在另一类中,则后者将不是排成类,而是位于继承层次结构之外,因此不能访问保护成员。但通过继承的到的将是派生类,因此他能够访问保护成员。
另一种需要使用私有继承的情况是需要重新定义虚函数。派生类可以重新定义虚函数,但包含类不能。使用私有继承,重新定义的函数将只能在类中使用,而不是公有的。

多重继承(MI)
为了解决多重继承而引入虚基类,也就是继承的两个类都含有相同函数的时候,产生无法识别该函数,引入了虚基类,只需要在调用某个父类的方法的时候,加上类名限定符即可
一个例子(注意这里为了能够进行显示转换需要使用virtual public方式继承)
[cpp]
// testMI.cpp : 定义控制台应用程序的入口点。
//

#include "stdafx.h"
#include "iostream"
using namespace std;
#include "string"

class Worker
{
public:
Worker( const string& Name, long Id ) : m_fullName( Name ), m_lId( Id )
{
}
Worker() : m_fullName( "no one" ), m_lId( 0L )
{
}
virtual ~Worker() = 0;
virtual void Set() = 0;
virtual void Show() const = 0;
protected:
void Data() co