1.继承与多肽-基础入门

原创 2016年05月31日 11:17:09

从本篇文章开始将要讲解C++里面最重要的内容:继承与多肽。为什么要把继承和多肽放在一块讲是因为多肽只能发生在父类和子类之间(也就是没有继承就没有多肽)。

 

继承与多肽我准备花费三个篇幅来讲解:

1.继承与多肽-基础入门

2.继承与多肽-项目实战

3.继承与多肽-实现原理

 

关于上面的三个篇幅我将采用三篇文章来讲解,今天这篇文章先讲解.继承与多肽的基础入门篇。

 

基础入门篇我主要是先讲解下和多肽有关的几个核心概念:函数重写、赋值兼容性原则、多肽

1.函数重写

说到函数重写大多数人肯定会和函数重载相混淆,如果有混淆的请看我的 “函数重载和函数重写的本质区别” 。函数重写就是子类定义了和父类一模一样的成员函数(包括参数个数、参数顺序、返回值都一模一样),函数体可以不一样。例如下面的代码:

#include <iostream>

using namespace std;

class Parent
{
protected:
	int nMoney;

public:
	// 父类构造函数 
	Parent()
	{
		nMoney = 10;
	}

	// 老爸炫富方法
	void showMoney()
	{
		cout << "Parent::showMoney() = " << nMoney << endl;
	}
};

class Child : public Parent
{
protected:
	int nMoney;
public:
	// 子类的构造函数
	Child()
	{
		nMoney = 100;	
	}
	// 孩子也有炫富的方法 和老爸一模一样 只是孩子挣的钱比较多了 老爸10万 孩子是老爸的十倍
	void showMoney()
	{
		cout << "Child::showMoney() = " << nMoney << endl;
	}	
}; 

int main()
{
	Child c;
	c.showMoney();

	return 0;
}

程序运行结果:Child::showMoney() = 100

我们可以看到父类和子类都有相同的属性 int nMoney(只是老爸是10万,而孩子却又100万),并且还有相同的炫富方法void showMoney()。上一节我们已经说过当父类和子类有相同的成员变量时,默认(在不适应作用于分辨符的情况)会访问子类那个。其实如果父类和子类有相同的成员函数,虽然父类的那个成员函数已经继承给子类,但是在用子类的对象去调用这个成员函数时,默认还是会使用子类的那个重写函数,也就是我们的c.showMeney()为什么会打印 Child::showMoney() = 100的原因,因为默认是使用子类的成员变量、子类的成员函数。这个在子类和父类都有的showMoney()函数,就是函数重写。简单的说,函数重写就是定义了一个和父类一样的函数,为了下面方便理解,我讲的比较多。

2.赋值兼容性原则

赋值兼容性原则概念:子类的对象可以当做父类使用。

赋值兼容性原则就是父类的指针和引用可以操作子类的对象,这一句话看似很简单,但是真的要是可以灵活用到你的工程上,你的工程将会变得非常容易管理。例如根据上面的代码我们在main函数中有如下定义:

 Child c1;

 Child c2;

 Parent *p1 = &c1;

 Parent &p2 = c2;

 

C++中什么样的指针或者引用必须指向什么样的对象,但是由于赋值兼容性原则,子类可以当做父类使用,所以一个父类的指针可以指向子类的对象,因为编译器会把子类当做父类。假设一下,如果编译器把c1和c2当做Child类型的对象,程序必然会报错,因为一个Parent指针指向了一个不是Parent类型的对象。所以编译器在这里是把c1和c2当做Parent类型的对象。这就是我们平时说的赋值兼容性原则。为了验证上面所说的,我们来看一个程序:

#include <iostream>

using namespace std;

class Parent
{
protected:
	int nMoney;

public:
	// 父类构造函数 
	Parent()
	{
		nMoney = 10;
	}

	// 老爸炫富方法
	void showMoney()
	{
		cout << "Parent::showMoney() = " << nMoney << endl;
	}
};

class Child : public Parent
{
protected:
	int nMoney;
public:
	// 子类的构造函数
	Child()
	{
		nMoney = 100;	
	}
	// 孩子也有炫富的方法 和老爸一模一样 只是孩子挣的钱比较多了 老爸10万 孩子是老爸的十倍
	void showMoney()
	{
		cout << "Child::showMoney() = " << nMoney << endl;
	}	
}; 

int main()
{
	Child c1;
	Child c2;
	Parent *p1 = &c1;  // 父类的指针指向子类的对象1
	Parent &p2 = c2;   // 父类的引用指向子类的对象2

	p1->showMoney();
	p2.showMoney();
	return 0;
}

程序输出结果:

Parent::showMoney() = 10
Parent::showMoney() = 10

疑问:

Parent *p1 = &c1;  这句代码明明是引用了c1,为什么还是调用了父类的炫富函数?

Parent &p2 = c2;   这句代码明明值指向了c2,为什么还是调用了父类的炫富函数?

 

答案:这个就是复制兼容性原则在搞鬼,因为编译器会把c1和c2当做父类的对象,所以当然会去使用父类的炫富函数。这个往往不是我们需要的,我们需要的往往是指向子类对象就使用子类的函数,指向父类对象就使用父类的函数。这样哦我们呢就可以引出多肽的概念了。

 

3.多肽:多肽就是一个调用语句可以实现多种状态。

下面我把上面的代码实现多肽,再看看运行结果,大家就可以理解多肽是个什么样的东西了。

#include <iostream>

using namespace std;

class Parent
{
protected:
	int nMoney;

public:
	// 父类构造函数 
	Parent()
	{
		nMoney = 10;
	}

	// 老爸炫富方法, 使用 virtual 关键字可以实现多台机制
	virtual void showMoney()
	{
		cout << "Parent::showMoney() = " << nMoney << endl;
	}
};

class Child : public Parent
{
protected:
	int nMoney;
public:
	// 子类的构造函数
	Child(int money)
	{
		nMoney = money;	
	}
	// 孩子也有炫富的方法和老爸一模一样 只是孩子挣的钱比较多了 老爸10万 孩子是老爸的十倍
	// 这里的关键字不使用也可以,因为当父类中使用了virtual,子类重写的函数自动的也会变成虚函数
	virtual void showMoney()
	{
		cout << "Child::showMoney() = " << nMoney << endl;
	}	
}; 

int main()
{
	Child  child1(10);  // 定义了一个 Child 类型的对象 child1,炫富值:10
	Child  child2(20);  // 定义了一个 Child 类型的对象 child2,炫富值:20
	Parent parent;      // 定义了一个 Parent 类型的对象 parent,炫富值:10
	Parent * p1;        // 定义了一个父类的指针,用来操作父类和子类对象使用

	p1 = &child1;       // 指向child1
	p1->showMoney();

	p1 = &child2;       // 指向child2
	p1->showMoney();  

	p1 = &parent;       // 指向parent
	p1->showMoney();  


	return 0;
}

程序运行结果:

Child::showMoney() = 10
Child::showMoney() = 20
Parent::showMoney() = 10

看似不起眼的结果背后却蕴藏了一个程序设计中非常常用的设计方法,下面我先讲解下这段代码。

大家有没有发现两个类除了子类的构造函数发生变化以外还有什么发生了变化?父类中被重写的函数加了一个 virtual 关键字,子类重写的那个函数也加了关键字 virtual 。这样就可以实现我们所说的多肽。mian函数里面定义了两个子类对象,炫富值分别是10和20,并且定义了一个父类的对象和指针。

我们可以发现虽然使用了同样调用语句p1->showMoney(),却产生了不同的结果,这就是上面说的一个调用语句可以实现多种状态。

 

到这里多肽已经讲完,总结下要实现多肽所必须的几个条件:

1.多肽是发生在父类和子类之间的,单一的一个类不可能实现多肽。

2.父类和子类必须发生重写函数,并且父类被重写的函数前面必须用 virtual 关键字进行修饰。

3.在使用多肽特性时,必须定义一个父类的指针或者引用。(这个在下一节 “继承与多肽-项目实战” 会详细讲解为什么要这样做)

 

在进入下一节之前,我们可以思考一个问题:

现在有一个父类P1,有50个子类 C1-C50继承了它,这50个子类中都重写了父类P1的某个函数(比如说showMoney()函数),50个子类每个子类都有对应的一个对象,总共也就是50个不同类型对象,现在要对这50个不同类型的对象全体炫富一次用程序怎么实现?

说明:我们上面的例子只是一个子类,用这个子类定义了两个同类型的对象,而上面问题说的是50个子类,每个子类定义1个对象,然后对每个对象炫下富。

 

下一节我们会用一个比较典型的小项目来深入讲解怎么在工程里面巧妙的使用多肽并且解决上面的问题。

 

 

 

 

 


 

 

 

 

 

 

 

 

 

 

 

版权声明:本文为博主原创文章,未经博主允许不得转载。

相关文章推荐

Java子类的构造方法与多态

(1) 可以使用父类中数据域的set方法为其设置初值; (2) 使用super()调用父类的无参构造方法或者super(parameters)调用与参数匹配的父类的构造方法,且super()或者su...

重拾java基础(八):继承、多肽总结

一、继承 1、在java编程中会遇到两个或者多个类中存在多个代码重复,这时我们就需要在这 两个或多个类中寻找他们的共同特点,然后寻找一个大的类别来包括,他们的共 同属性和方法,这...

java之继承,封装,多肽

一,封装 理解:把对象的属性和操作(或服务)结合为一个独立的整体,并尽可能的隐藏对象内部实现细节 例如:我们写一个简单的输入两个数和一个操作符(+,-,*,/)的的运算, 可以把具体操作和属性封装成一...

Nescafe41 ProblemA 异化多肽 多项式求逆

题目大意:、 思路: 搞出CC的生成函数F(x)F(x),那么: 长度为11的答案为F(x)F(x) 长度为22的答案为F2(x)F^2(x) … 故最终的答案为 F(x)+F2(x...
  • PoPoQQQ
  • PoPoQQQ
  • 2015年04月28日 14:09
  • 1450

NesCafe41 异化多肽 NTT实现多项式求逆

NesCafe41 异化多肽 NTT实现多项式求逆
  • wzq_QwQ
  • wzq_QwQ
  • 2015年09月11日 19:42
  • 1536

香港千姿凯诗特多肽面膜

凯诗特诚招代理商
  • zdc243
  • zdc243
  • 2014年12月06日 22:31
  • 26

Spring基础:快速入门spring cloud(1):Spring Cloud介绍

分布式系统, 微服务, Java, 当这三个词放到一起的时候, 很多人自然而然地就会想起Spring Cloud. Spring Cloud是Spring总多的Project中的一个,它提供了一整套的...

Android基础入门教程——8.1.1 Android中的13种Drawable小结 Part 1

从本节开始我们来学习Android中绘图与动画中的一些基础知识,为我们进阶部分的自定义 打下基础!而第一节我们来扣下Android中的Drawable!Android中给我们提供了多达13种的 D...

Dubbo学习总结(1)——Dubbo入门基础与实例讲解

Dubbo是阿里巴巴SOA服务化治理方案的核心框架,每天为2,000+个服务提供3,000,000,000+次访问量支持,并被广泛应用于阿里巴巴集团的各成员站点。Dubbo是一个分布式服务框架,致力于...

Android基础入门教程——5.2.1 Fragment实例精讲——底部导航栏的实现(方法1)

在上一节中我们对Fragment进行了一个初步的了解,学习了概念,生命周期,Fragment管理与 Fragment事务,以及动态与静态加载Fragment。从本节开始我们会讲解一些Fragment...
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:1.继承与多肽-基础入门
举报原因:
原因补充:

(最多只允许输入30个字)