1.继承的基本语法:class A:继承方式(public,protected,private) B;
//A为子类(派生类),B为父类(基类):子类成员包括两部分(1继承父类的,2自己特有的)
1.1好处:减少重复的代码
2.继承方式
class Base
{
public:int a;
protected:int b;
private:int c;
};
class SonA :public Base
{
public:
void func()
{
a = 10;//继承为公有权限,类内可以访问
b = 10;//继承为保护权限,类内可以访问
//c = 10;//父类私有权限,继承后类内也访问不了
}
};
class SonB :protected Base
{
public:
void func()
{
a = 20;//继承为保护权限,类内可以访问
b = 20;//继承为保护权限,类内可以访问
//c =20;//父类私有权限,继承后类内也访问不了
}
};
class SonC :private Base
{
public:
void func()
{
a = 30;//继承为私有权限,类内可以访问
b = 30;//继承为私有权限,类内可以访问
//c = 30;//父类私有权限,继承后类内也访问不了
}
};
void test01()
{
SonA sonA;
sonA.a = 10; //继承为公有权限,类外不可以访问
//sonA.b = 10;继承为保护权限,类外不可以访问
//sonA.c = 10;继承为私有权限,类外不可以访问
}
void test02()
{
SonB sonB;
//sonA.a =20;继承为保护权限,类外不可以访问
//sonB.b =20;继承为保护权限,类外不可以访问
//sonB.c =20;继承为私有权限,类外不可以访问
}
void test03()
{
SonC sonC;
//sonC.a = 30;继承为私有权限,类外不可以访问
//sonC.b = 30;继承为私有权限,类外不可以访问
//sonC.c = 30;继承为私有权限,类外不可以访问
}
3.继承中的对象模型(继承父类所有成员,访问不到的是被编译器隐藏了,还是会占内存)
class Base
{
public:int a;
protected:int b;
private:int c;
};
class Son :public Base
{
public:int c;//继承的父类的私有属性访问不了,但也还是继承下来了,只是被编译器隐藏了
};
void test01()
{
Son son;
cout << "sizeof(son)=" << sizeof(son) << endl;//输出为16(继承父类的12,自身的4)
}
命令(cl /d1 reportSingleClassLayout查看的类 所属文件名)
首先定位到当前cpp文件位置
然后输入命令cl /d1 reportSingleClassLayoutSon test.cpp
4.继承中的构造和析构函数
4.1子类继承父类后,当创建子类对象时,也会调用父类的构造函数
4.2顺序:先调用父类的构造函数再调用子类的构造函数,析构函数则相反
5.继承同名成员处理方式
访问子类同名成员:直接访问即可
访问父类同名成员:要加作用域(父类名::)
class Base
{
public:
Base()
{
m_a = 10;
}
void func()
{
cout << "Base类func()的调用" << endl;
}
void func(int)
{
cout << "Son类func(int)的调用" << endl;
}
public:
int m_a;
};
class Son :public Base
{
public:
Son()
{
m_a = 10;
}
void func()
{
cout << "Son类func()的调用" << endl;
}
public:
int m_a;
};
void test01()
{
Son son;
cout << son.m_a << endl;
cout << son.Base::m_a << endl;//访问同名的父类的成员要加作用域
son.func();
son.Base::func();//访问同名的父类的成员要加作用域
son.Base::func(10); //son.func(10);有重载的也要加作用域
}
6.同名的静态成员处理
6.1出现同名成员函数,子类会隐藏父类中的所有同名的成员函数,要加作用域才可以访问
6.2与上述5一样只是多了可以通过类名访问成员函数,注意静态成员变量(类内定义,类外初始化)
class Base
{
public:
static void func()
{
cout << "Base类func()的调用" << endl;
}
static void func(int)
{
cout << "Base类func(int)的调用" << endl;
}
public:
static int m_a;
};
int Base::m_a = 10;
class Son :public Base
{
public:
static void func()
{
cout << "Son类func()的调用" << endl;
}
public:
static int m_a;
};
int Son::m_a = 100;
void test01()
{
Son son;
//通过对象访问成员变量
cout << son.m_a << endl;
cout << son.Base::m_a << endl;//访问同名的父类的成员要加作用域
//通过类名访问
cout << Son::m_a << endl;
cout << Son::Base::m_a << endl;
}
void test02()
{
//通过对象访问成员函数
Son son;
son.func();
son.Base::func();
//通过类名访问
//出现同名成员函数,子类会隐藏父类中的所有同名的成员函数,要加作用域才可以访问
Son::func();
Son::Base::func();
Son::Base::func(10);
}
7.多继承语法
7.1语法:class 子类:继承方式 父类1,继承方式 父类2........
7.2多继承可能引发父类中有同名成员出现,需要加作用域区分
class Base1
{
public:
Base1()
{
m_a = 10;
}
public:
int m_a;
};
class Base2
{
public:
Base2()
{
m_a = 20;
}
public:
int m_a;
};
class Son :public Base1,public Base2
{
public:
Son()
{
m_c = 30;
m_d = 40;
}
public:
int m_c;
int m_d;
};
void test01()
{
Son son;
cout << "sizeof(son)=" << sizeof(son) << endl;//输出16,Base1--4,Base2--4,本身Son--8
cout << "Base1.m_a="<<son.Base1::m_a << endl;//多继承可能引发父类中有同名成员出现,需要加作用域区分
cout << "Base2.m_a=" <<son.Base2::m_a << endl;
}
8.菱形继承问题及解决方法
8.1两个子类继承同一个父类,同时一个子子类继承这两个子类
8.2菱形继承又称钻石继承
8.3子子类继承两个父类资源,实际只需要一份,造成资源浪费
8.4利用虚拟继承可以解决(实际继承的是指针,指的同一块地址)
class Aninal
{
public:
int m_age;
};
//继承前加virtual关键字后,变为虚拟类
//此时公共的父类Animal称为虚基类
class Sheep:virtual public Aninal{};
class Tuo : virtual public Aninal {};
class SheepTuo :public Sheep, public Tuo{};
void test01()
{
SheepTuo st;
st.Sheep::m_age = 18;
st.Tuo::m_age = 28;
cout << st.Sheep::m_age << endl;
cout << st.Tuo::m_age << endl;
cout << st.m_age << endl;//输出都为28,实质是三个不同的指针指向同一个Animal.m_age
}
底层逻辑: