21天学C++(十六)高级继承

完整目录、平台简介、安装环境及版本:参考《21天学C++ 概览》

十六、高级继承

16.1 包容

一个类的数据成员有可能是另一个类的对象,称之为外层类包含内层类;has-a

  • 公有继承:类可以继承接口(纯虚函数),可能还有实现,获得接口的关系是IS-A关系;
  • 包容:类可以获得实现(通过内层类对象访问其公有函数),但是不能获得接口,即HAS-A关系;
#include <iostream>
#include <string.h>
using namespace std;

class String
{
public:
	// constructors
	String();
	String(const char *const);
	String(const String &);
	~String();

	// overloaded operators
	char & operator[](int offset);
	char operator[](int offset) const;
	String operator+(const String&);
	void operator+=(const String&);
	String & operator= (const String &);

	// General accessors
	int GetLen()const { return itsLen; }
	const char * GetString() const { return itsString; }
	static int ConstructorCount;

private:
	String (int);         // private constructor
	char * itsString;
	unsigned short itsLen;

};

// default constructor creates string of 0 bytes
String::String()
{
	itsString = new char[1];
	itsString[0] = '\0';
	itsLen=0;
	cout << "\tDefault string constructor\n";
	ConstructorCount++;
}

// private (helper) constructor, used only by
// class methods for creating a new string of
// required size.  Null filled.
String::String(int len)
{
	itsString = new char[len+1];
	for (int i = 0; i<=len; i++)
		itsString[i] = '\0';
	itsLen=len;
	cout << "\tString(int) constructor\n";
	ConstructorCount++;
}

// Converts a character array to a String
String::String(const char * const cString)
{
	itsLen = strlen(cString);
	itsString = new char[itsLen+1];
	for (int i = 0; i<itsLen; i++)
		itsString[i] = cString[i];
	itsString[itsLen]='\0';
	cout << "\tString(char*) constructor\n";
	ConstructorCount++;
}

// copy constructor
String::String (const String & rhs)
{
	itsLen=rhs.GetLen();
	itsString = new char[itsLen+1];
	for (int i = 0; i<itsLen;i++)
		itsString[i] = rhs[i];
	itsString[itsLen] = '\0';
	cout << "\tString(String&) constructor\n";
	ConstructorCount++;
}

// destructor, frees allocated memory
String::~String ()
{
	delete [] itsString;
	itsLen = 0;
	cout << "\tString destructor\n";
}

// operator equals, frees existing memory
// then copies string and size
String& String::operator=(const String & rhs)
{
	if (this == &rhs)
		return *this;
	delete [] itsString;
	itsLen=rhs.GetLen();
	itsString = new char[itsLen+1];
	for (int i = 0; i<itsLen;i++)
		itsString[i] = rhs[i];
	itsString[itsLen] = '\0';
	return *this;
	// cout << "\tString operator=\n";
}

//non constant offset operator, returns
// reference to character so it can be
// changed!
char & String::operator[](int offset)
{
	if (offset > itsLen)
		return itsString[itsLen-1];
	else
		return itsString[offset];
}

// constant offset operator for use
// on const objects (see copy constructor!)
char String::operator[](int offset) const
{
	if (offset > itsLen)
		return itsString[itsLen-1];
	else
		return itsString[offset];
}

// creates a new string by adding current
// string to rhs
String String::operator+(const String& rhs)
{
	int  totalLen = itsLen + rhs.GetLen();
	String temp(totalLen);
	int i, j;
	for (i = 0; i<itsLen; i++)
		temp[i] = itsString[i];
	for (j = 0; j<rhs.GetLen(); j++, i++)
		temp[i] = rhs[j];
	temp[totalLen]='\0';
	return temp;
}

// changes current string, returns nothing
void String::operator+=(const String& rhs)
{
	unsigned short rhsLen = rhs.GetLen();
	unsigned short totalLen = itsLen + rhsLen;
	String  temp(totalLen);
	int i, j;
	for (i = 0; i<itsLen; i++)
		temp[i] = itsString[i];
	for (j = 0; j<rhs.GetLen(); j++, i++)
		temp[i] = rhs[i-itsLen];
	temp[totalLen]='\0';
	*this = temp;
}

int String::ConstructorCount = 0; 
#include "MyString.h"

class Employee
{
public:
	Employee();
	Employee(char *, char *, char *, long);
	~Employee();
	Employee(const Employee&);
	Employee & operator= (const Employee &);

	const String & GetFirstName() const
	{ return itsFirstName; }
	const String & GetLastName() const { return itsLastName; }
	const String & GetAddress() const { return itsAddress; }
	long GetSalary() const { return itsSalary; }

	void SetFirstName(const String & fName)
	{ itsFirstName = fName; }
	void SetLastName(const String & lName)
	{ itsLastName = lName; }
	void SetAddress(const String & address)
	{ itsAddress = address; }
	void SetSalary(long salary) { itsSalary = salary; }
private:
	String    itsFirstName;
	String    itsLastName;
	String    itsAddress;
	long      itsSalary;
};

Employee::Employee():
itsFirstName(""),
itsLastName(""),
itsAddress(""),
itsSalary(0)
{}

Employee::Employee(char * firstName, char * lastName,
				   char * address, long salary):
itsFirstName(firstName),
itsLastName(lastName),
itsAddress(address),
itsSalary(salary)
{}

Employee::Employee(const Employee & rhs):
itsFirstName(rhs.GetFirstName()),
itsLastName(rhs.GetLastName()),
itsAddress(rhs.GetAddress()),
itsSalary(rhs.GetSalary())
{}

Employee::~Employee() {}

Employee & Employee::operator= (const Employee & rhs)
{
	if (this == &rhs)
		return *this;

	itsFirstName = rhs.GetFirstName();
	itsLastName = rhs.GetLastName();
	itsAddress = rhs.GetAddress();
	itsSalary = rhs.GetSalary();

	return *this;
}
int main(){
	Employee Edie("Jane","Doe","1461 Shore Parkway", 20000);
	Edie.SetSalary(50000);
	String LastName("Levine");
	Edie.SetLastName(LastName);//程序结束再析构
	Edie.SetFirstName(“Edythe”);//生成临时变量,然后调用赋值构造函数,赋值完成后,被析构

	cout << "Name: "<< Edie.GetFirstName().GetString()<< " " << Edie.GetLastName().GetString()<<endl;
	cout << "Address: " << Edie.GetAddress().GetString()<<endl;
	cout << "Salary: " << Edie.GetSalary()<<endl;
	return 0;
}

执行结果如下:

        String(char*) constructor
        String(char*) constructor
        String(char*) constructor
        String(char*) constructor
        String(char*) constructor
        String destructor
Name: Edythe Levine
Address: 1461 Shore Parkway
Salary: 50000
        String destructor
        String destructor
        String destructor
        String destructor
请按任意键继续. . .

16.1.2 按值和按引用传递

#include "MyString.h"

class Employee
{
public:
	Employee();
	Employee(char *, char *, char *, long);
	~Employee();
	Employee(const Employee&);
	Employee & operator= (const Employee &);

	const String & GetFirstName() const
	{ return itsFirstName; }
	const String & GetLastName() const { return itsLastName; }
	const String & GetAddress() const { return itsAddress; }
	long GetSalary() const { return itsSalary; }

	void SetFirstName(const String & fName)
	{ itsFirstName = fName; }
	void SetLastName(const String & lName)
	{ itsLastName = lName; }
	void SetAddress(const String & address)
	{ itsAddress = address; }
	void SetSalary(long salary) { itsSalary = salary; }
private:
	String    itsFirstName;
	String    itsLastName;
	String    itsAddress;
	long      itsSalary;
};

Employee::Employee():
itsFirstName(""),
itsLastName(""),
itsAddress(""),
itsSalary(0)
{}

Employee::Employee(char * firstName, char * lastName,
				   char * address, long salary):
itsFirstName(firstName),
itsLastName(lastName),
itsAddress(address),
itsSalary(salary)
{}

Employee::Employee(const Employee & rhs):
itsFirstName(rhs.GetFirstName()),
itsLastName(rhs.GetLastName()),
itsAddress(rhs.GetAddress()),
itsSalary(rhs.GetSalary())
{}

Employee::~Employee() {}

Employee & Employee::operator= (const Employee & rhs)
{
	if (this == &rhs)
		return *this;

	itsFirstName = rhs.GetFirstName();
	itsLastName = rhs.GetLastName();
	itsAddress = rhs.GetAddress();
	itsSalary = rhs.GetSalary();

	return *this;
}

void PrintFunc(Employee);
void rPrintFunc(const Employee&);

int main()
{
	Employee Edie("Jane","Doe","1461 Shore Parkway", 20000);
	Edie.SetSalary(20000);
	Edie.SetFirstName("Edythe");
	String LastName("Levine");
	Edie.SetLastName(LastName);

	cout << "Constructor count: " ;
	cout << String::ConstructorCount << endl;
	rPrintFunc(Edie);
	cout << "Constructor count: ";
	cout << String::ConstructorCount << endl;
	PrintFunc(Edie);
	cout << "Constructor count: ";
	cout << String::ConstructorCount << endl;
	return 0;
}
void PrintFunc (Employee Edie)
{
	cout << "Name: ";
	cout << Edie.GetFirstName().GetString();
	cout << " " << Edie.GetLastName().GetString();
	cout << ".\nAddress: ";
	cout << Edie.GetAddress().GetString();
	cout << ".\nSalary: " ;
	cout << Edie.GetSalary();
	cout << endl;
}

void rPrintFunc (const Employee& Edie)
{
	cout << "Name: ";
	cout << Edie.GetFirstName().GetString();
	cout << " " << Edie.GetLastName().GetString();
	cout << "\nAddress: ";
	cout << Edie.GetAddress().GetString();
	cout << "\nSalary: " ;
	cout << Edie.GetSalary();
	cout << endl;
}

执行结果如下:

        String(char*) constructor
        String(char*) constructor
        String(char*) constructor
        String(char*) constructor
        String destructor
        String(char*) constructor
Constructor count: 5
Name: Edythe Levine
Address: 1461 Shore Parkway
Salary: 20000
Constructor count: 5
        String(String&) constructor
        String(String&) constructor
        String(String&) constructor
Name: Edythe Levine.
Address: 1461 Shore Parkway.
Salary: 20000
        String destructor
        String destructor
        String destructor
Constructor count: 8
        String destructor
        String destructor
        String destructor
        String destructor
请按任意键继续. . .

16.2 私有继承

所有基本成员变量和函数不管在基类中的实际访问级别如何,均被看作是声明为私有;

私有继承不涉及继承接口,只继承实现(HAS-A关系,类似包容)

  • 子类需要通过成员函数访问基类成员变量和成员函数;
#include <iostream>
using namespace std;

class BaseClass{
public:
	BaseClass(){}
	~BaseClass(){}
	//virtual void testInterface() = 0;//has –a关系,
	int getImple(){return 3;}//私有继承后,只能被子类的成员函数访问
private:
	int iPriVal;
};
class InheriateClass : private BaseClass{
public:
	InheriateClass():BaseClass(){};
	~InheriateClass(){};
	int getVal(){return getImple();}//可以通过成员函数访问基类,继承实现
};
int main(){
	InheriateClass inheriateClass;
	inheriateClass.getVal();/
	//inheriateClass.getImple();
	//inheriateClass.testInterface();
}

执行结果如下:

请按任意键继续. . .
  • 当使用多个基类时,不建议使用公有继承和私有继承,应使用包容;
  • 当基类中的成员不能用于派生类的客户时,不能使用公有继承;

16.3 友元

16.3.1 友元类

  • 把私有性成员变量或函数暴露给另外一个类,则须把这个类声明为一个友元。
  • 友元关系不可以继承;
  • 友元关系不可以互通;
#include <iostream>
using namespace std;

class FriendClass{
public:
	friend class TestClass;
	FriendClass(){PriVal = 3;}
	~FriendClass(){}
	int GetVal(){return 2;}
private:
	int PriVal;
	int GetPriVal(){return 4;}
};

class TestClass{
public:
	int getTest(){return friendClass.PriVal;}
	int getTest1(){return friendClass.GetVal();}
	int getTest2(){return friendClass.GetPriVal();}
private:
	FriendClass friendClass;
};
int main(){
	TestClass testClass;
	cout<<testClass.getTest()<<endl;
	cout<<testClass.getTest1()<<endl;
	cout<<testClass.getTest2()<<endl;
	return 0;
}

执行结果如下:

3
2
4
请按任意键继续. . .

16.3.2 友元函数1

把访问级别不授予整个类,而是授予该类的一两个函数,如1;

#include <iostream>
using namespace std;
class Animal;
void setValue(Animal& , int);

class Animal{
public:
	friend void  setValue( Animal&, int);
	int GetWeight()const { return itsWeight; }
	int GetAge() const { return itsAge; }
private:
	int itsWeight;
	int itsAge;
};

void setValue(Animal& theAnimal, int theWeight)
{
	theAnimal.itsWeight = theWeight;
}

int main()
{
	Animal peppy;
	setValue(peppy,5);
	return 0;
}

执行结果如下:

请按任意键继续. . .

16.3.3 友元函数2(常用:重载运算符)

   String s1("String One ");
   String s2("String Two ");
   char *c1 = { "C-String One " } ;

   cout << "s1: " << s1.GetString() << endl;
   cout << "s2: " << s2.GetString() << endl;
   cout << "c1: " << c1 << endl;
  String  s3 = s1 + s2;   //调用String.operator+(const String &);
   cout << "s3: " << s3.GetString() << endl;
  String  s4 = s1 + c1;//调用String.operator+(const char *const)或String.operator+(const String &);
   cout << "s4: " << s4.GetString() << endl;
  String  s5 = c1 + s2;//不能对C字符串调用operator+,编译错误。需要通过friend解决
   cout << "s5: " << s5.GetString() << endl;
#include <iostream>
#include <string.h>
using namespace std;

// Rudimentary string class
class String
{
public:
	// constructors
	String();
	String(const char *const);
	String(const String &);
	~String();

	// overloaded operators
	char & operator[](int offset);
	char operator[](int offset) const;
	String operator+(const String&);
	String operator+(const char *const);
	friend String operator+(const String&, const String&);
	void operator+=(const String&);
	String & operator= (const String &);

	// General accessors
	int GetLen()const { return itsLen; }
	const char * GetString() const { return itsString; }

private:
	String (int);         // private constructor
	char * itsString;
	unsigned short itsLen;
};

// default constructor creates string of 0 bytes
String::String()
{
	itsString = new char[1];
	itsString[0] = '\0';
	itsLen=0;
	// cout << "\tDefault string constructor" << endl;
	// ConstructorCount++;
}

// private (helper) constructor, used only by
// class methods for creating a new string of
// required size.  Null filled.
String::String(int len)
{
	itsString = new char[len+1];
	for (int i = 0; i<=len; i++)
		itsString[i] = '\0';
	itsLen=len;
	// cout << "\tString(int) constructor" << endl;
	// ConstructorCount++;
}

// Converts a character array to a String
String::String(const char * const cString)
{
	itsLen = strlen(cString);
	itsString = new char[itsLen+1];
	for (int i = 0; i<itsLen; i++)
		itsString[i] = cString[i];
	itsString[itsLen]='\0';
	// cout << "\tString(char*) constructor" << endl;
	// ConstructorCount++;
}

// copy constructor
String::String (const String & rhs)
{
	itsLen=rhs.GetLen();
	itsString = new char[itsLen+1];
	for (int i = 0; i<itsLen;i++)
		itsString[i] = rhs[i];
	itsString[itsLen] = '\0';
	// cout << "\tString(String&) constructor" << endl;
	// ConstructorCount++;
}

// destructor, frees allocated memory
String::~String ()
{
	delete [] itsString;
	itsLen = 0;
	// cout << "\tString destructor" << endl;
}

// operator equals, frees existing memory
// then copies string and size
String& String::operator=(const String & rhs)
{
	if (this == &rhs)
		return *this;
	delete [] itsString;
	itsLen=rhs.GetLen();
	itsString = new char[itsLen+1];
	for (int i = 0; i<itsLen;i++)
		itsString[i] = rhs[i];
	itsString[itsLen] = '\0';
	return *this;
	// cout << "\tString operator=" << endl;
}

//non constant offset operator, returns
// reference to character so it can be
// changed!
char & String::operator[](int offset)
{
	if (offset > itsLen)
		return itsString[itsLen-1];
	else
		return itsString[offset];
}

// constant offset operator for use
// on const objects (see copy constructor!)
char String::operator[](int offset) const
{
	if (offset > itsLen)
		return itsString[itsLen-1];
	else
		return itsString[offset];
}

// creates a new string by adding current
// string to rhs
String String::operator+(const String& rhs)
{
	int  totalLen = itsLen + rhs.GetLen();
	String temp(totalLen);
	int i, j;
	for (i = 0; i<itsLen; i++)
		temp[i] = itsString[i];
	for (j = 0, i = itsLen; j<rhs.GetLen(); j++, i++)
		temp[i] = rhs[j];
	temp[totalLen]='\0';
	cout<<"operator + String"<<endl;
	return temp;
}
// Converts a character array to a String
String String::operator+(const char * const cString)
{
	int  totalLen = itsLen + strlen(cString);
	String temp(totalLen);
	int i, j;
	for (i = 0; i<itsLen; i++)
		temp[i] = itsString[i];
	for (j = 0, i = itsLen; j<strlen(cString); j++, i++)
		temp[i] = cString[j];
	temp[totalLen]='\0';	
	cout<<"operator + char*"<<endl;
	return temp;
}

// creates a new string by adding
// one string to another
String operator+(const String& lhs, const String& rhs)
{
	int  totalLen = lhs.GetLen() + rhs.GetLen();
	String temp(totalLen);
	int i, j;
	for (i = 0; i<lhs.GetLen(); i++)
		temp[i] = lhs[i];
	for (j = 0, i = lhs.GetLen(); j<rhs.GetLen(); j++, i++)
		temp[i] = rhs[j];
	temp[totalLen]='\0';	
	cout<<"operator + friend"<<endl;
	return temp;
}

int main()
{
	String s1("String One ");
	String s2("String Two ");
	char *c1 = { "C-String One " } ;
	String s3;
	String s4;
	String s5;

	cout << "s1: " << s1.GetString() << endl;
	cout << "s2: " << s2.GetString() << endl;
	cout << "c1: " << c1 << endl;
	s3 = s1 + s2;
	cout << "s3: " << s3.GetString() << endl;
	s4 = s1 + c1;
	cout << "s4: " << s4.GetString() << endl;
	s5 = c1 + s2;
	cout << "s5: " << s5.GetString() << endl;
	return 0;
}

执行结果如下:

s1: String One
s2: String Two
c1: C-String One
operator + String
s3: String One String Two
operator + char*
s4: String One C-String One
operator + friend
s5: C-String One String Two
请按任意键继续. . .

16.3.4 重载插入运算符 <<

让String拥有cout功能,即

String theString; 
cout<<theString.getString()<<endl; //通常打印串 
Cout<<theString<<endl; //重载后打印串
#include <iostream>
#include <string.h>
using namespace std;

class String
{
public:
	// constructors
	String();
	String(const char *const);
	String(const String &);
	~String();

	// overloaded operators
	char & operator[](int offset);
	char operator[](int offset) const;
	String operator+(const String&);
	void operator+=(const String&);
	String & operator= (const String &);
	friend ostream& operator<<
		( ostream& theStream,String& theString);
	// General accessors
	int GetLen()const { return itsLen; }
	const char * GetString() const { return itsString; }

private:
	String (int);         // private constructor
	char * itsString;
	unsigned short itsLen;
};


// default constructor creates string of 0 bytes
String::String()
{
	itsString = new char[1];
	itsString[0] = '\0';
	itsLen=0;
	// cout << "\tDefault string constructor" << endl;
	// ConstructorCount++;
}

// private (helper) constructor, used only by
// class methods for creating a new string of
// required size.  Null filled.
String::String(int len)
{
	itsString = new char[len+1];
	for (int i = 0; i<=len; i++)
		itsString[i] = '\0';
	itsLen=len;
	// cout << "\tString(int) constructor" << endl;
	// ConstructorCount++;
}

// Converts a character array to a String
String::String(const char * const cString)
{
	itsLen = strlen(cString);
	itsString = new char[itsLen+1];
	for (int i = 0; i<itsLen; i++)
		itsString[i] = cString[i];
	itsString[itsLen]='\0';
	// cout << "\tString(char*) constructor" << endl;
	// ConstructorCount++;
}

// copy constructor
String::String (const String & rhs)
{
	itsLen=rhs.GetLen();
	itsString = new char[itsLen+1];
	for (int i = 0; i<itsLen;i++)
		itsString[i] = rhs[i];
	itsString[itsLen] = '\0';
	// cout << "\tString(String&) constructor" << endl;
	// ConstructorCount++;
}

// destructor, frees allocated memory
String::~String ()
{
	delete [] itsString;
	itsLen = 0;
	// cout << "\tString destructor" << endl;
}

// operator equals, frees existing memory
// then copies string and size
String& String::operator=(const String & rhs)
{
	if (this == &rhs)
		return *this;
	delete [] itsString;
	itsLen=rhs.GetLen();
	itsString = new char[itsLen+1];
	for (int i = 0; i<itsLen;i++)
		itsString[i] = rhs[i];
	itsString[itsLen] = '\0';
	return *this;
	// cout << "\tString operator=" << endl;
}

//non constant offset operator, returns
// reference to character so it can be
// changed!
char & String::operator[](int offset)
{
	if (offset > itsLen)
		return itsString[itsLen-1];
	else
		return itsString[offset];
}

// constant offset operator for use
// on const objects (see copy constructor!)
char String::operator[](int offset) const
{
	if (offset > itsLen)
		return itsString[itsLen-1];
	else
		return itsString[offset];
}

// creates a new string by adding current
// string to rhs
String String::operator+(const String& rhs)
{
	int  totalLen = itsLen + rhs.GetLen();
	String temp(totalLen);
	int i, j;
	for (i = 0; i<itsLen; i++)
		temp[i] = itsString[i];
	for (j = 0; j<rhs.GetLen(); j++, i++)
		temp[i] = rhs[j];
	temp[totalLen]='\0';
	return temp;
}

// changes current string, returns nothing
void String::operator+=(const String& rhs)
{
	unsigned short rhsLen = rhs.GetLen();
	unsigned short totalLen = itsLen + rhsLen;
	String  temp(totalLen);
	int i, j;
	for (i = 0; i<itsLen; i++)
		temp[i] = itsString[i];
	for (j = 0, i = 0; j<rhs.GetLen(); j++, i++)
		temp[i] = rhs[i-itsLen];
	temp[totalLen]='\0';
	*this = temp;
}

// int String::ConstructorCount =
ostream& operator<< ( ostream& theStream,String& theString)
{
	theStream << theString.itsString;
	return theStream;
}

int main()
{
	String theString("Hello world.");
	cout << theString;
	return 0;
}

执行结果如下:

Hello world.请按任意键继续. . .

发表回复