一、类继承
用已有的类来建立专用的类,实现代码重用
父类-子类 基类-派生类
1.概念
用已有的类来建立专用类的编程技术;
2.目的
实现代码重用
3.父类/基类 和 子类/派生类
父类:已有的类叫父类,是抽象类
子类:由基类派生出来的类叫派生类/子类,是父类的具体化
4.语法形式
class 子类名 : 权限限定符 基类名1, 权限限定符 基类名2....
{
//class body
};
#include <iostream>
using namespace std;
class Base{
public:
Base(int val ):val(val){//int val = 0
cout<<__func__<<__LINE__<<endl;
}
~Base(){
cout<<__func__<<__LINE__<<endl;
}
public:
void setval(int);
int getval();
private:
int val;
};
void Base::setval(int x){
this->val = x;
}
int Base::getval(){
return this->val;
}
class Inherit : public Base{ // :
public:
Inherit(int val=1,int x=50):myval(val),Base(x){
cout<<__func__<<__LINE__<<endl;
}
~Inherit(){
cout<<__func__<<__LINE__<<endl;
}
public:
void setmyval(int x);
int getmyval();
private:
int myval;
};
void Inherit::setmyval(int x){
this->myval = x;
}
int Inherit::getmyval(){
setval(5);
return this->myval;
}
class Demo:public Inherit{
public:
Demo(int x=2):demoval(x){
cout<<__func__<<__LINE__<<endl;
}
~Demo(){
cout<<__func__<<__LINE__<<endl;
}
public:
void setdemoval(int x);
int getdemoval();
private:
int demoval;
};
void Demo::setdemoval(int x){
this->demoval = x;
}
int Demo::getdemoval(){
return this->demoval;
}
int main()
{
Demo obj(100);
cout<<obj.getval()<<endl;
cout<<obj.getmyval()<<endl;
cout<<obj.getdemoval()<<endl;
return 0;
}
二、继承方式以及子类中的权限
基类 | |
public继承 | 基类的public成员 -> 子类的public成员 |
基类的protected成员 -> 子类的protected成员 | |
基类的private成员只能通过基类的接口访问 | |
protected继承 | 基类的public成员 -> 子类的protected成员 |
基类的protected成员 -> 子类的protected成员 | |
基类的private成员只能通过基类的接口访问 | |
private继承 | 基类的public成员 -> 子类的private成员 |
基类的protected成员 -> 子类的private成员 | |
基类的private成员只能通过基类的接口访问 | |
注意: | protected成员只能在类内部或子类内部访问 |
三、构造和析构的顺序、默认继承权限
1.注意
每个类都有自己的构造和析构
2.顺序
先构造基类对象,再构造子类对象
先析构子类对象,再析构基类对象
3.默认继承权限:private
四、继承的四种关系(暂定)
is-a | 公有继承,基类-派生类,派生类可作为新的基类 比如水果-苹果 |
has-a | 聚合关系,一种类中有另一种类的对象 比如午餐-水果 |
is-implemented-a | 作为xx来实现,比如数组实现栈,这并不能通过公有继承is-a来实现 |
is-like-a | 在继承中,仅覆盖了父类方法即为Is-a;若在覆盖父类方法基础上有新增方法,则为Is-like-a。 一个类既有A的特性,又有B的特性,这并不能通过公有继承is-a来实现,引申出多重继承 |
五、多重继承
#include<iostream>
using namespace std;
class Base{
public:
Base()
{
cout << __func__ << ":" << __LINE__ << endl;
}
~Base()
{
cout << __func__ << ":" << __LINE__ << endl;
}
public:
void prnmsg()
{
cout << __func__ << ":" << __LINE__ << endl;
}
};
class Man : public Base{
public:
Man()
{
cout << __func__ << ":" << __LINE__ << endl;
}
~Man()
{
cout << __func__ << ":" << __LINE__ << endl;
}
};
class Wolf : Base{
public:
Wolf()
{
cout << __func__ << ":" << __LINE__ << endl;
}
~Wolf()
{
cout << __func__ << ":" << __LINE__ << endl;
}
};
//多重继承
class WolfMan : public Wolf,public Man{
public:
WolfMan()
{
cout << __func__ << ":" << __LINE__ << endl;
}
~WolfMan()
{
cout << __func__ << ":" << __LINE__ << endl;
}
};
int main()
{
WolfMan obj;
obj.prnmsg();//多重继承产生二义性
return 0;
}
六、多重继承产生的二义性
由于所继承的父类又都来自同一个父类,而产生二义性的问题
通过添加成员名限定来消除二义性(虚函数来实现)
比如 obj.Man::prnmsg();
七、面试题
const char *p | p指向的东西不能通过p来更改 |
char const *p | 同上 |
char * const p | p的指向不能更改,比如不能p++了 |
char const * const p | p的指向不能更改,p指向的东西也不能通过p来更改 |
const char * const p | 同上 |
打印sizeof(p),1字节=8位 | |
结果是8 | 64位 |
结果是4 | 32位 |
地址补充:64位二进制机,4位表示一位十六进制数,所以地址有16位,只用到了12位。32/4=8位十六进制数。 |
写程序,判断一个操作系统是16位还是32位的。不能用 sizeof() 函数。
#include <iostream>
using namespace std;
int main(){
int a = ~0;
if (a<65536)
cout<<"16"<<endl;
else
cout<<"32"<<endl;
return 0;
}
void * ( * (*fp1)(int))[10]; | fp1是函数指针,int是参数,void *是函数返回的指针,指向数组,数组有10个元素,每个元素都是一个void *类型的指针 |
float (*(* fp2)(int,int,int))(int); | fp2是一个函数指针,函数参数为3个int,函数的返回值为一个指针,这个指针指向参数为int的函数 int (*p)(int x, int y); |
int (* ( * fp3)())[10](); | fp3是一个函数指针,函数的参数为空,函数的返回值是一个指向数组的指针,数组有10个元素,每个元素存的都是返回值为int 型的函数指针,指向的函数参数为空 |
总结:函数指针形式int (*p)() ;指针数组形式 int * p[3](int *是指针类型) 返回值可以是指针,这个指针可指向数组,数组可以是个指针数组 可以先看函数指针 (*p)(参数) ,再看这个函数指针的返回值 也可以先看指针数组,xxx * xxx [10] |