继承和派生
现实写照
父亲“派生”出儿子
儿子“继承”自父亲
派生和派生,本质是相同的,只是从不同的角度来描述。
继承和派生在UML 中的表示
注意是“空心三角箭头”,从子类【派生的类】指向父类【被继承的类】
父类,也称为“基类”
除了“构造函数”和“析构函数”
父类的所有成员函数,以及数据成员,都会被子类继承!
代码实现
Son.h
#pragma once
#include "Father.h"
#include <iostream>
class Son :public Father{
public:
Son(const char* name,int age ,const char*game);
Son();
string description();
~Son();
string getGame();
private:
string game;
};
son.cpp
#include "Son.h"
#include "Father.h"
#include <sstream>
//创建son对象时候,会调用构造函数!
//会调用父类的构造
//再调用自己的构造函数
Son::Son(const char* name, int age,const char*game) : Father(name, age)
{
cout << __FUNCTION__ << endl;
this->game = game;
}
Son::Son()
{
}
string Son::description()
{
stringstream des;
des << "name" << getName() << "age" << getAge() << "Game" << getGame();
return des.str();
}
Son::~Son()
{
cout << __FUNCTION__ << endl;
}
string Son::getGame()
{
return game;
}
Father.h
#pragma once
#include <string>
using namespace std;
class Father
{
public:
Father(const char* name,int age);
~Father();
Father();
string getName();
int getAge();
string description();
private:
string name;
int age;
};
Father.cpp
#include "Father.h"
#include <sstream>
#include <iostream>
Father::Father()
{
}
Father::Father(const char* name, int age)
{
cout << __FUNCTION__ << endl;
this->name = name;
this->age = age;
}
Father::~Father()
{
}
string Father::getName()
{
return string();
}
int Father::getAge()
{
return 0;
}
string Father::description()
{
stringstream des;
des <<"name" << name << "Age" << age;
return des.str();
}
main.cpp
#include "Father.h"
#include "Son.h"
int main(void) {
Father wjl("王健林", 68);
Son wsc("王思聪", 32, "电竞");
cout << wjl.description() << endl;
//子类对象调用方法时 先在自己的定义中去寻找 如果有 ,就调用自己定义的 方法
//如果找不到 就从父类的方法中去找 如果有 就调用这个方法
cout << wsc.description() << endl;
cout << wsc.getName() << "游戏:" << wsc.getGame() << endl;
system("pause");
return 0;
}
// 子类的成员函数中, 不能访问从父类继承的private成员 可以使用protect
子类对象调用方法时 先在自己的定义中去寻找 如果有 ,就调用自己定义的 方法
如果找不到 就从父类的方法中去找 如果有 就调用这个方法
子类, 一般会添加自己的数据成员/成员函数,
或者, 重新定义从父类继承的方法!!! 子类对象就会调用自己重新定义的方法, 不会调用父类的同名方法
子类对象的分布
设置vs编译器:
在命令行中添加选项:(打印指定类的内存分布)
/d1 reportSingleClassLayoutFather /d1 reportSingleClassLayoutSon
重新生成:
(x64)
x86
cout << sizeof(wlj) << endl; // 32
cout << sizeof(yangGuo) << endl; // 60
说明:成员函数,不占用对象的内存空间,但是也被子类继承了!!
protected 保护权限
为什么要使用protected保护权限
子类的成员函数中,不能直接访问父类的private成员,已经这些成员已经被继承下来了,但是却不能访问。
只有通过父类的public函数来间接访问,不是很方便。
比如,刚才Demo中Father类中的name和age成员。
解决方案:
把name和age定义为protected访问访问权限。
效果:
Son类的成员函数中,可以直接访问它的父类的protected成员。
但是在外部,别人又不能直接通过Son对象来访问这些成员。
一个类, 如果希望, 它的成员, 可以被自己的子类(派生类)直接访问,
但是, 又不想被外部访问那么就可以把这些成员, 定义为 protected访问权限!!!
访问权限总结:
public
外部可以直接访问.
可以通过对象来访问这个成员
private
外部不可以访问
自己的成员函数内, 可以访问
Father内的所有成员函数内, 可以直接访问name
protected
protected和private非常相似
和private的唯一区别:
protecte: 子类的成员函数中可以直接访问
private: 子类的成员函数中不可以访问
派生和继承的各种方式
-
(公有)继承[使用最频繁]
父类中定义的成员(数据成员和函数成员)被继承后,访问权限不变!
public --> public
protected --> protected
private --> private
-
(私有)继承
父类的成员(数据成员和函数成员)被继承后,访问权限变为private
public --> private
protected --> private
private --> private
-
(保护继承)
public --> protected
protected --> protected
private --> private
小结:
public 继承全不变
private继承全变私
protected继承只把public降级为protected