is-a
来源:互联网 发布:寝室文明公约知乎 编辑:程序博客网 时间:2024/05/21 06:24
-----------------siwuxie095
is-a
在C++ 中,is-a (是一个)的概念就相当于 隐形眼镜也是眼镜
如果眼镜是基类的话,那隐性眼镜就是眼镜的派生类
再如:定义人类、工人类、士兵类,其中:工人类和士兵类分别继承
人类,就可以把每一个工人的对象称之为人的对象,也可以把每一个
士兵的对象称之为人的对象
基于这种理论,在程序中就有很多更加灵活的玩法了,如下:
先实例化Soldier 对象 s1,当实例化 Person 对象 p1 时,让 p1 直接
接收s1,即 用 s1 去实例化 p1,这样做,在语法上是正确的,因为一
个士兵也是一个人,用士兵去初始化人是 OK的,再用Person 的指针
p2 指向 Soldier 的对象 s1,显然也是 OK 的
但是,不能说一个人也是一个士兵,即将人的对象p1 赋值给士兵的对
象 s1 是有问题的,同时,用士兵的指针 s2 指向人的对象 p1 也是有问
题的
综上所述:
(1)派生类的对象可以赋值给基类或子类的对象可以赋值给父类
(2)基类的指针可以指向派生类的对象或父类的指针可以指向子类的对象
既然如此,就可以将基类的指针或基类的对象或基类的引用,
作为函数的参数,来使函数可以接收所传入的子类的指针或对
象(或者基类的指针或对象)
如下:
存储结构
(1)将子类的对象赋值给父类的对象,或用子类的对象初始化
父类的对象
如果父类含有m_strName 和 m_iAge 两个数据成员,那么子类
在继承父类时,一定也含有 m_strName和m_iAge 这两个数据
成员,同时,子类还有自身的数据成员
当用子类的对象向父类的对象赋值或用子类的对象初始化父类的
对象时,其本质就是将子类当中从父类继承下来的数据成员赋值给
父类的对象,子类当中其它的数据此时就会被截断,即丢失
因为,对于父类对象来说,它只能接收自己拥有的数据成员的数据,
而无法接收其它的数据
(2)用父类的指针指向一个子类对象
如果是用父类的指针指向一个子类的对象,那么父类的指针也
只能访问到父类所拥有的数据成员,而无法访问到子类所拥有
的数据成员,即父类指针指向子类对象时,只能通过父类指针
去访问父类原有的数据成员和成员函数,无法访问子类独有的
数据成员和成员函数
程序 1:
Person.h:
#include <string>
using namespace std;
class Person
{
public:
Person(string name ="Jim");
virtual ~Person();
void play();
protected:
string m_strName;
};
Person.cpp:
#include"Person.h"
#include <iostream>
using namespace std;
Person::Person(string name)
{
m_strName = name;
cout <<"Person()" << endl;
}
Person::~Person()
{
cout <<"~Person()" << endl;
}
void Person::play()
{
cout <<"Person--play()" << endl;
cout << m_strName << endl;
}
Soldier.h:
#include"Person.h"
class Soldier:public Person
{
public:
Soldier(string name ="James", int age = 20);
virtual ~Soldier();
void work();
protected:
int m_iAge;
};
Soldier.cpp:
#include"Soldier.h"
#include <iostream>
using namespace std;
Soldier::Soldier(string name,int age)
{
m_strName = name;
m_iAge = age;
cout <<"Soldier()" << endl;
}
Soldier::~Soldier()
{
cout <<"~Soldier()" << endl;
}
void Soldier::work()
{
cout <<"Soldier--work()" << endl;
cout << m_strName <<"," << m_iAge<< endl;
}
main.cpp:
#include<stdlib.h>
#include"Soldier.h"
#include <iostream>
using namespace std;
int main(void)
{
Soldier soldier;
soldier.work();
cout << endl;
//通过父类的对象、指针、引用来指向子类的对象
//即用子类的对象来初始化父类的对象、指针、引用
//
//而不能用父类对象去初始化子类即is-a的关系
//在初始化时父类只会得到子类从父类继承来的数据成员
//而子类自己的数据成员则会被截断丢失
//
//假如改为: Person person1; person1=soldier; 这样就会多执行一次构造函数
Person person1 = soldier;
person1.play();
//父类指针也只能指向内存中子类从父类继承来的数据成员所在的内存
Person *person2 = &soldier;
person2->play();
Person &person3 = soldier;
person3.play();
cout << endl;
//当Person类的指针从堆中指向Soldier类的对象时使用虚析构函数
//如果不使用虚析构函数那么堆中的内存就无法释放导致内存泄露
//即前面的 virtual 是为下面这段代码用的
Person *p =new Soldier;
p->play();
//如果不使用虚析构函数,delete p 时就只会调用Person类的析构函数,
//而指针 p 指向Soldier类对象时却依次执行了父类和子类的构造函数,
//即子类对象没有释放掉
delete p;
p = NULL;
system("pause");
return0;
}
//当使用父类的指针指向从堆中申请的子类的对象时
//又想要通过父类的指针释放这块从堆中申请的内存就必须使用虚析构函数
//
//当给父类的析构函数加上关键字 virtual 后这个关键字会被继承下去
//即子类的析构函数也是虚析构函数即便不写关键字 virtual
//不过推荐子类的析构函数前也写上 virtual
运行一览:
程序 2:
Person.h:
#include <string>
using namespace std;
class Person
{
public:
Person(string name ="Jim");
~Person();
void play();
protected:
string m_strName;
};
Person.cpp:
#include"Person.h"
#include <iostream>
using namespace std;
Person::Person(string name)
{
m_strName = name;
cout <<"Person()" << endl;
}
Person::~Person()
{
cout <<"~Person()" << endl;
}
void Person::play()
{
cout <<"Person--play()" << endl;
cout << m_strName << endl;
}
Soldier.h:
#include"Person.h"
class Soldier :public Person
{
public:
Soldier(string name ="James", int age = 20);
~Soldier();
void work();
protected:
int m_iAge;
};
Soldier.cpp:
#include"Soldier.h"
#include <iostream>
using namespace std;
Soldier::Soldier(string name,int age)
{
m_strName = name;
m_iAge = age;
cout <<"Soldier()" << endl;
}
Soldier::~Soldier()
{
cout <<"~Soldier()" << endl;
}
void Soldier::work()
{
cout <<"Soldier--work()" << endl;
cout << m_strName <<"," << m_iAge << endl;
}
main.cpp:
#include<stdlib.h>
#include"Soldier.h"
#include <iostream>
using namespace std;
//参数是父类的对象
//因为这里是对象在调用test1()时会实例化一个临时对象(在参数传进来时)
//并通过这个临时对象来调用play()函数
//test1()执行完毕后临时对象被销毁会执行析构函数
void test1(Person p)
{
p.play();
}
//参数是父类的引用
//不会产生新的临时变量效率更高(推荐)
void test2(Person &p)
{
p.play();
}
//参数是父类的指针
//不会产生新的临时变量效率更高(推荐)
void test3(Person *p)
{
p->play();
}
//在公有继承中 is-a的关系在函数参数传递时的体现
int main(void)
{
Soldier s;
Person p;
cout << endl;
test1(s);
test1(p);
cout << endl;
//使用父类的引用作参数也可以接收父类的对象以及子类的对象
test2(s);
test2(p);
cout << endl;
test3(&s);
test3(&p);
cout << endl;
system("pause");
return0;
}
运行一览:
【made by siwuxie095】
- is-a
- is-a has-a
- is-a&has-a
- is-a, is-like-a, has-a
- is-a, is-like-a, has-a
- Is is A Turning Point?
- 关键字is 、as,is a 、has a
- a job is a job
- is-a VS has-a
- is-a And has-a
- is-a 与 has-a
- “is a” 和”has a“
- Is -A 与Has - A
- HAS-A和IS--A
- UML has a/ is a
- “is a” 和”has a“
- is-a和has-a
- java is-a has-a
- Matlab入门程序
- 博为峰JavaEE技术文章 —— Hibernate域模型(3)物理命名策略
- Java 用正则表达式判断输入的字符串是否为手机号码
- 线程学习第一篇
- 网易游戏数据挖掘实习生面试经历
- is-a
- 关于service中intent-filter data属性的一个小坑
- GDOI2017 旅游记
- {小结}GDOI2017 论自卑心理的产生
- git merge
- 二分贪心—D
- 老司机忠告:千万千万不要运行的 Linux 命令
- MongoDB入门(2)--增删改查
- Bootstrap下拉菜单