AOP-Chap18-Inheritance

  • Inheritance is the ability to declare a class (called the child class or subclass or derived class) in such a way that it obtains all of the fields and methods of another class (called the parent class or super class or base class)
  • The child class can have more fields and methods of its own added to it and can override the behavior of the methods it inherited
  • is-a relationship
  • has-a relationship --> inheritance is inappropriate. Instead, one should have a field for the other—the Button class should declare a field of type string for its text

1 Another Conceptual Example

  • can inherit again from a class that is itself a child class, using it as the parent class of a third class
  • inheritance hierarchy—the collection of all classes that share a common “ancestor” class (parent class, “grandparent” class, etc.)
  • arrow --> is-a

2 Writing Classes with Inheritance

class BankAccount {
	double balance;
	unsigned long acctNumber;
public:
	void deposit(double amount); 
	double withdraw(double amount); 
	double getBalance() const;	
};
class InvestmentAccount : public BankAccount { //子类
	vector<pair<Stock *, double> > stocks;
	unsigned tradesThisMonth;	
public:
	void buyStock(Stock whichStock, double numShares); 
	void sellStock(Stock whichStock, double numShares); 
	double getMarketValue() const;	
};	
  • also add constructors and destructors to each class as needed and write the method bodies (either inline or separately)
  • not re-declare the fields or methods that the child class is inheriting from its parent
  • if we do declare fields of the same name as those in the parent class, we end up with objects that have two different fields of the same name --> if we added a duplicated field called balance, code in InvestmentAccount would reference it by default, and would refer to the inherited field by BankAccount::balance 不要这样做
  • public access specifier --> public inheritance --> public members remain public, and private members remain private
  • private inheritance --> all inherited members become private in the child class
  • protected inheritance --> make public members of the parent class into protected members of the child class. Members of a class may be declared protected, which means that they may be accessed by members of the class or by members of any of its child classes
class A {
protected:
	int x;
};
class B : public A {
	void someFunction() { 
		x++; //they may only be accessed through a pointer/reference/variable of the child class’s own type --> 这里实际是implicit this pointer, which has type B const * --> void someFunction(A * anA) { anA->x++;}错误
	}	
};	
  • code outside of classes A and B (and any other child classes of B) would not be able to access x directly 但可以用friend

3 Construction and Destruction

  • constructor顺着继承顺序由祖先到子类逐渐构造,type从A到B最终到C(C的代码开始前就变C)
  • destructor相反,先destroy子类字段,最后到ancestor --> it stops if any parent class’s destructor is trivial
  • constructor可能被overload,因此每一步可以选择不同的constructor --> 如果不显示致电哪个constructor则使用默认的;如果没有默认构造器或默认构造器是private,则编译报错;如果希望显式地调用其他构造函数,将父类构造函数的调用作为初始化列表的第一个元素
class BankAccount {
	double balance;
	unsigned long acctNumber;
	static unsigned long nextAccountNumber;
public: //2个构造器
	BankAccount() : balance(0), acctNumber(nextAccountNumber) {
  		nextAccountNumber++;
	}
	BankAccount(double b) : balance(b), acctNumber(nextAccountNumber) {
  		nextAccountNumber++;
	}
};
class InvestmentAccount : public BankAccount {
	vector<pair<Stock *, double> > stocks;
	unsigned tradesThisMonth;		
public: //2个构造器
	InvestmentAccount() : tradesThisMonth(0) { } //implicit call to the default constructor (as if it were the first element of the initializer list)
	InvestmentAccount(double balance) : BankAccount(balance), tradesThisMonth(0) { }	//pass that argument to the BankAccount constructor that takes a double for the initial balance.
};
  • destructors do not take arguments, so there is no issue of specifying which one to call or what arguments to pass it
  • Constructing and destroying objects that use inheritance
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    BankAccount是trivial,因此不用去BankAccount的destructor,直接free掉
    在这里插入图片描述

4 Subtype Polymorphism

  • polymorphism—which allows the same code to operate on multiple types
  • Subtype polymorphism arises when one type (InvestmentAccount) is a subtype of another type (BankAccount), meaning that an instance of InvestmentAccount is substitutable for an instance of BankAccount
  • polymorphism is restricted by the access modifier used in inheriting the parent class
  • public inheritance --> polymorphism may be freely used anywhere
  • private or protected inheritance --> polymorphism is only permissible where a field with that access restriction could be used (in the class or its friends for private inheritance, or in the class, its subclasses, or any of their friends for protected inheritance)
  • subtype polymorphism allows to treat an instance of a child class as if it were an instance of one of its parent classes
  • 但是多态仅限于在pointers和references应用
void f(A * a) {
 ...
}
void g(B * b) {
	f(b); //uses polymorphism
}	 
  • 每个要放父类type的时候都可以放一个子类的type --> is-a relationship
//Polymorphism allows us to place any subclass of BankAccount into allAccounts
class BankAccount {
	double interestRate;
	//other fields elided
public:
	//other methods and constructors elided
	void accrueInterest(double fractionOfYear) {
		balance += balance * interestRate * fractionOfYear;
	}
};

class Bank {
	vector<BankAccount *> allAccounts;		
public:
	InvestmentAccount * createInvestmentAccount(double balance){
		InvestmentAccount * newAccount = new InvestmentAccount(balance);
		allAccounts.push_back(newAccount); //use polymorphism
		return newAccount;
	}
	void accrueInterestOnAllAccounts(double fractionOfYear) {
		vector<BankAccount *>::iterator it = allAccounts.begin(); 
		/*即使vector中的指针实际上可能指向InvestmentAccounts、retimentaccounts或MarginAccounts(除了普通的BankAccounts之外),can iterate over them all with one iterator and call accrueInterest on each of them
		*/
		while (it != allAccounts.end()) { 
  			BankAccount * currentAccount = *it;
 			currentAccount->accrueInterest(fractionOfYear);
  			++it;
  		}
  	}
};			
  • 多态只能应用于指针或reference的原因:InvestmentAccount比BankAccount占用更多的内存空间。因此,如果我们直接拥有InvestmentAccount(也就是说,不是通过指针或引用),它需要一个比BankAccount“更大的框”。如果一个框架或对象是为BankAccount设计的,它将只有一个适合银行账户的大小的框,而不是InvestmentAccount。然而,不管指针指向什么,它们的大小都是相同的
BankAccount * b = new InvestmentAccount();
/*
If call b->buyStock(someStock,amount) —as far as the compiler is concerned, b points at a BankAccount, and BankAccount objects do not have a buyStock method
*/
  • static type is the type obtained by the type checking rules of the compiler, which only uses the declared types of variables. --> static type of *b is BankAccount
  • dynamic type of the object is the type of object that is actually pointed at --> dynamic type of *b is InvestmentAccount
  • arrow in b’s box points at an InvestmentAccount object
  • compiler only works with the static types

5 Method Overriding

#include <iostream>
#include <cstdlib>

class A {
public:
	void sayHi() {
		std::cout << "Hello from class A\n";
	}
}class B : public A {
public: 
	void sayHi() {
		std::cout << "Hello from class B\n";
	}
};
int main(void) {
	A anA;
	B aB;
	A * ptr = &aB; 
	anA.sayHi(); 
	aB.sayHi(); 
	ptr->sayHi(); //ptr的静态类型是A *
	return EXIT_SUCCESS;
};

/*
Hello from class A
Hello from class B
Hello from class A
*/			

请添加图片描述

  • static patch分派 --> 静态类型决定method to call
  • dynamic patch分派 --> 动态类型决定method to call --> declare it as virtual
#include <iostream>
#include <cstdlib>

class A {
public:
	virtual void sayHi() { //virtual at the front
		std::cout << "Hello from class A\n";
	}
}class B : public A {
public: 
	virtual void sayHi() {
		std::cout << "Hello from class B\n";
	}
};
int main(void) {
	A anA;
	B aB;
	A * ptr = &aB; 
	anA.sayHi(); 
	aB.sayHi(); 
	ptr->sayHi(); //ptr的静态类型是A *
	return EXIT_SUCCESS;
};

/*
Hello from class A
Hello from class B
Hello from class B
*/			
  • 方法的虚声明必须在父类
  • 一旦一个方法被声明为虚方法,它在所有子类(及其子类等等)中仍然是虚方法,即使没有显式地这样声明
  • Method dispath in C++
    在这里插入图片描述
    在这里插入图片描述

在这里插入图片描述

  • Classes that contain virtual methods are never POD (plain old data) types, as they contain extra information to allow dynamic dispatch
  • draw objects with their type as part of their “box” if they contain virtual methods手画时
  • Dynamically dispatching methods during object construction and destruction
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    请添加图片描述
  • The pitfalls缺陷 of non-virtual destructors when objects are used polymorphically
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
  • 无论何时使用可能涉及多态性的类,其destructor都应该声明为virtual
class MarginAccount : public InvestmentAccount {
	//other things here.
	virtual bool buyStock(Stock * s, double numShares) { 
		double cost = getCost(s) * numShares;
		double borrowAmount = 0;
		if (balance < cost) {
			borrowAmount = cost - balance;
			if (marginUsed + borrowAmount < marginLimit) {
     			balance += borrowAmount;
      			marginUsed += borrowAmount;
    		}
			else {
				return false;
			} 
		}
		if (InvestmentAccount::buyStock(s, numShares)) { //如果想调用父类的方法版本,可以通过使用完全限定名显式地请求它来实现
			return true;
		}
		balance -= borrowAmount; 
		marginUsed -= borrowAmount; 
		return false;
	}
};	
  • 重载的方法可能有更大的访问范围(如果父方法声明为private,子方法可以声明为public)。但是,它不能变得更加严格(不能用私有方法重载公共方法)
  • 被重载的方法可以以covariant协变 fashion更改返回类型,即子类中的返回类型是父类中的返回类型的子类型
class Animal {
public:
	virtual Animal * getFather() { 
		//code here
	}
	virtual Animal * getMother() {
		//code here
	}
};
class Cat : public Animal {
public:
	virtual Cat * getFather() { //返回Cat *合法,是Animal*的子类型;但返回value而非指针非法,多态只对指针或reference有用
		//code here
	}
	virtual Cat * getMother() {
		//code here
	}
};				

6 Abstract Methods and Classes

  • abstract method or a pure virtual member function --> there is no way I can define this method in this class, but any child class of mine must override this method with a real implementation.”
class Shape {
public:
	virtual bool containsPoint(const Point & p) const = 0; //在最后用 = 0且必须有virtual
};	
  • 当一个类中有一个抽象方法时,这个类就变成了一个抽象类
  • 抽象类不能被实例化,即不能执行new Shape,也不能将变量声明为Shape类型。但是,可以将变量(或参数)声明为Shape *或Shape &类型用于polymorphically to reference an instance of a concrete subclass of Shape—one that has provided actual implementations for all of its abstract methods, such as Circle, Rectangle, or Triangle
  • 抽象类的任何子类也是抽象的,除非它为其父类中的所有抽象方法定义了具体实现 --> 可以创建一个子类,它既定义了containsPoint,又声明了自己的新抽象方法,这样的类也是抽象的
  • Executing code with abstract classes
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
  • 漏洞:如果抽象类的构造器中的代码调用了抽象method,那么object的动态类型就是抽象类,没有implementation --> program crash

7 Inheritance and Templates

  • templates不能与继承完全组合,主要与virtual method的相关规则有关

7.1 Aspects That Are Composable

  • 让一个模板化的类继承另一个类,继承一个模板化的类的实例化,或者两者混合(让一个模板化的类继承另一个模板化的类的实例化)是完全可以的
//instantiating the parent class with the template parameter of the child
template<typename T>
class MyFancyVector : public std::vector<T> {
	...
};	
//parameterize a class in terms of what its parent is --> mixin in Chap29
template<typename T>
class MyClass : public T {
	...
};	
//a templated class to have virtual methods
template<typename T>
class Myclass {
public:
	//perfectly fine
	virtual int computeSomething(int x) { 
		//some code
	}
	//also fine
	virtual void someFunction() = 0; 
	//still fine, good idea if used polymorphically 
	virtual ~MyClass() {}
};	

7.2 Aspects That Are Not Composable

  • A templated method cannot be virtual
//错误:
class MyClass {
public:
	//illegal: virtual templated function
	template<typename X> virtual
	int doSomething(const X & arg) {
   		//some code here...
	}
};
/*
error: templates may not be ’virtual’
       template<typename X> virtual
*/	

请添加图片描述

  • A templated function cannot override an inherited method
    请添加图片描述
    请添加图片描述
    Child class does not actually override the method of the same name from the Parent class
    Instead, we have a non-virtual template method in the child class and inherit the virtual method from the parent class.
Parent * p = new Child();
p->something();
/*
Parent::something\n
*/
  • Virtual methods are specialized when an instance is made --> If a method is virtual, then the compiler must specialize (and thus type check) it whenever it must create an instance of the class 结合17

8 Planning Your Inheritance Hierarchy

在这里插入图片描述
在这里插入图片描述
请添加图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值