目录
一:基类 派生类 继承中的内存占用
派生类内存占用 = 父类数据成员内存 + 自身特有成员内存;示例如下
#include<iostream>
using namespace std;
#include "CLabel.h"
#include"CEdit.h"
#include"CButton.h"
#include"CTools.h"
#include"CLogin.h"
#include"CtrBase.h"
#include"Father.h"
#include"Child.h"
int main()
{
cout<<sizeof(CtrBase)<<endl;//36
//派生类内存占用 父类数据成员内存+自身特有成员内存
cout<<sizeof(CEdit)<<endl;//48
}
二:基类 派生类 继承中的执行顺序
继承过程中构造和析构的执行顺序:
基类构造 派生类构造 派生类析构 基类析构;示例如下
#include<iostream>
using namespace std;
#include "CLabel.h"
#include"CEdit.h"
#include"CButton.h"
#include"CTools.h"
#include"CLogin.h"
#include"CtrBase.h"
#include"Father.h"
#include"Child.h"
int main()
{
CEdit editName(34,10,10,3,"",8,2,1);
//基类CtrBase带参构造函数
//CEdit带参构造--派生类
//派生类--CEdit析构函数
//基类CtrBase析构函数
}
三:基类的成员属性 使用protected修饰
如下,子类不能调用父类的私有成员
//error C2248: 'startX' : cannot access protected member declared in class 'CtrBase'
#include<iostream>
using namespace std;
#include "CLabel.h"
#include"CEdit.h"
#include"CButton.h"
#include"CTools.h"
#include"CLogin.h"
#include"CtrBase.h"
#include"Father.h"
#include"Child.h"
int main()
{
CEdit editName(34,10,10,3,"",8,2,1);
cout<<editName.startX<<endl;
//error C2248: 'startX' : cannot access protected member declared in class 'CtrBase'
}
通过在基类中为private修饰的成员属性 设计get方法,为子类提供访问接口,这样的操作不能体现出继承的优势性,
因此,对于基类的成员属性,使用protected修饰,子类可以直接访问
四:面向对象程序设计 继承 源码示例
通过以下 父与子 的案例 【深入学习面向对象程序设计中的继承思想】
Father.h:(基类 头文件)
#ifndef FATHER_H
#define FATHER_H
#include<iostream>
using namespace std;
class Father
{
public:
Father();
~Father();
void print();
int pub;
int getPublic();
int getPrivate();//get方法类外访问
int getProtected();
private:
int num;
protected:
int pro;
};
#endif
Father.cpp:(基类 源文件)
#include"Father.h"
Father::~Father()
{
cout<<"父类的析构函数"<<endl;
}
Father::Father()
{
this->num = 100;//private
this->pro = 100;//protected
this->pub = 100;//public
cout<<"父类的构造函数"<<endl;
}
void Father::print()
{
cout<<"父类print:private num="<<this->num<<endl;//private
}
int Father::getPublic()
{
return this->pub;
}
int Father::getPrivate()
{
return this->num;
}
int Father::getProtected()
{
return this->pro;
}
Child.h:(派生类 头文件)
#ifndef CHILD_H
#define CHILD_H
#include"Father.h"
class Child : public Father
{
public:
Child();
~Child();
void print();
void speak();
void change();
private:
int num; //继承自父类的成员变量
int hobby; //子类自身的成员变量
};
#endif
Child.cpp:(派生类 源文件)
下面代码中 父类中private修饰的成员属性,在子类获取不到,报错,注释掉即可(已注释)
#include"Child.h"
Child::~Child()
{
cout<<"子类的析构函数"<<endl;
}
Child::Child()
{
cout<<"子类的构造函数"<<endl;
}
//派生类重定义基类函数
//子类中有跟父类同名的函数 优先走子类
void Child::print()
{
cout<<"子类根据自身特殊需求重定义父类的函数"<<endl;
}
void Child::speak()
{ //1.public公有继承
cout<<"子类的成员特有函数"<<endl;
// cout<<"private:"<<Father::num<<endl; //父类private 子类获取不到
cout<<"protected:"<<Father::pro<<endl; //父类protected 子类获取的到
cout<<"public:"<<Father::pub<<endl; //父类public 子类获取的到
//error C2248: 'num' : cannot access private member declared in class 'Father'
/* 父类的构造函数
子类的构造函数
子类的成员特有函数
protected:100
public:100
子类的析构函数
父类的析构函数*/
}
//子类成员内部无法访问private
void Child::change()
{
// Father::num = 100; //报错
Father::pro = 100;
Father::pub = 100;
}
get方法获取私有成员变量
在基类中为自己的私有的成员属性 设计get方法,提供类外访问的接口,子类就可以通过调用基类的get方法访问基类的私有成员属性(这样体现不出来继承的优势,因此,基类的成员属性若是要给派生类访问,使用protected修饰基类的成员属性即可)
void Child::speak()
{ //1.public公有继承
cout<<"子类的成员特有函数"<<endl;
cout<<"private:"<<Father::getPrivate()<<endl; //get方法: 父类private 子类获取的到
cout<<"protected:"<<Father::pro<<endl; // 父类protected子类获取的到
cout<<"public:"<<Father::pub<<endl; // 父类public 子类获取的到
/* 父类的构造函数
子类的构造函数
子类的成员特有函数
private:100
protected:100
public:100
子类的析构函数
父类的析构函数 */
}
main.cpp:(主入口测试)
#include<iostream>
using namespace std;
#include "CLabel.h"
#include"CEdit.h"
#include"CButton.h"
#include"CTools.h"
#include"CLogin.h"
#include"CtrBase.h"
#include"Father.h"
#include"Child.h"
int main()
{
Child a;
a.speak();
}
小结:基类【想要子类继承】的成员属性用protected修饰
#ifndef CTRBASE_H
#define CTRBASE_H
#define LABEL 1
#define EDIT 2
#define BUTTON 3
class CtrBase
{
public:
CtrBase();
~CtrBase();
CtrBase(int x,int y,int w,int h,char *pcontent);
void show();
protected: //基类成员属性用protected修饰
int startX;
int startY;
int width;
int height;
char content[20]; //内容
};
#endif
派生类继承基类的时候 一般使用 公有public继承 如下
class CLabel:public CtrBase
子类可以继承父类所有成员属性(包括私有),只是父类private修饰的成员属性,子类访问不到,需要使用get方法来访问 (继承 & 访问 是不同的 子类可以继承父类所有 不代表 子类可以访问父类所有)
派生类继承基类的时候若是使用私有继承,子类仍然可以get set方法访问父类private成员属性;但是子类的子类就不能get set方法继续访问了
调用方式
类名::(域运算符)
对象.(点运算符)
五:重定义
派生类重定义基类函数
子类有和父类 函数原型完全一样 会优先走子类 ---》 重定义
基类 函数原型和派生类一样 如下
void Father::print()
{
cout<<"父类print:private num="<<this->num<<endl;//private
}
派生类 函数原型和基类一样 如下
//派生类重定义基类函数
//子类中有跟父类同名的函数 优先走子类
void Child::print()
{
cout<<"子类根据自身特殊需求重定义父类的函数"<<endl;
}
main.cpp 主入口测试
#include<iostream>
using namespace std;
#include "CLabel.h"
#include"CEdit.h"
#include"CButton.h"
#include"CTools.h"
#include"CLogin.h"
#include"CtrBase.h"
#include"Father.h"
#include"Child.h"
int main()
{
Child a;
a.print();
//父类的构造函数
//子类的构造函数
//子类根据自身特殊需求重定义父类的函数
//子类的析构函数
//父类的析构函数
}
由结果不难看出,派生类会隐藏基类的方法,走自己的方法
小结:重定义函数的函数原型和基类中被重定义函数的函数原型必须完全相同
如:父与子都有void print(); 【函数原型完全一样】会导致基类的成员函数被隐藏,走子类的方法
什么时候重定义:
当父类的函数里面的操作不足以满足子类,子类就可以写与父类函数类型相同的函数来进行重定义
重载和重定义:重载参数不一样 但 重定义整个函数声明都一样(整个函数原型都一致)
类指针 :
类也是一种数据类型
指针操作对象 用->运算符