继承基本语法
继承好处:减少重复代码
class 子类 : 继承方式 父类
子类也称派生类
父类也称基类
派生类的成员包括了自己本身的成员(特有属性),
还包括了从基类继承的成员(共有属性)。
#include<iostream>
#include<string>
using namespace std;
class A
{
public:
void f1()
{
cout << "f1" << endl;
}
void f2()
{
cout << "f2" << endl;
}
void f3()
{
cout << "f3" << endl;
}
};
class B:public A
{
public:
void F1()
{
cout << "F1" << endl;
}
};
void t1()
{
A a;
cout << "A" << endl;
a.f1();
a.f2();
a.f3();
B b;
cout << "B" << endl;
b.f1();
b.f2();
b.f3();
b.F1();
}
int main()
{
t1();
system("pause");
return 0;
}
继承方式
继承方式有三种:
- 公共继承
- 保护继承
- 私有继承
公共继承:父类的公共权限在子类中仍然是公共权限,父类的保护权限在子类中仍是保护权限,父类的私有权限不能访问。
class A
{
public:
int a;
protected:
int b;
private:
int c;
};
class B:public A
{
public:
int a;
protected:
int b;
//private:int c 不能访问
};
保护继承:父类的公共权限和保护权限在子类中都变为保护权限,父类的私有权限不能访问。
class A
{
public:
int a;
protected:
int b;
private:
int c;
};
class B:public A
{
protected://类外不能访问
int a;
int b;
//private:int c 不能访问
};
私有权限:父类的公共权限和保护权限在子类都变成私有权限,父类的私有权限不能访问。
class A
{
public:
int a;
protected:
int b;
private:
int c;
};
class B:public A
{
private://类外不能访问
int a;
int b;
//int c 不能访问
};
继承中的对象模型
父类的私有成员也会被继承下去,只是被隐藏了。
#include<iostream>
#include<string>
using namespace std;
class A
{
public:
int a;
protected:
int b;
private:
int c;//同样继承下去,只是被隐藏了
};
class B:public A
{
public:
int d;
};
void t1()
{
cout << "sizeof(B)=" << sizeof(B)<<endl;
}
int main()
{
t1();
system("pause");
return 0;
}
构造与析构顺序
父类先构造然后子类再构造,
子类先析构然后父类再析构。
#include<iostream>
#include<string>
using namespace std;
class A
{
public:
A()
{
cout << "父类构造函数" << endl;
}
~A()
{
cout << "父类析构函数" << endl;
}
};
class B :public A
{
public:
B()
{
cout << "子类构造函数" << endl;
}
~B()
{
cout << "子类析构函数" << endl;
}
};
void t1()
{
B p;
}
int main()
{
t1();
system("pause");
return 0;
}
同名成员的处理
- 访问子类同名成员直接访问即可
- 访问父类同名成员需要加作用域
如果子类中出现和父类同名的成员函数,子类的同名成员会隐藏掉父类中所有同名成员函数。想访问到父类中被隐藏的同名成员函数,需要加作用域。
#include<iostream>
#include<string>
using namespace std;
class A
{
public:
A()
{
a = 1;
}
void f()
{
cout << "父类函数调用" << endl;
}
void f(int a)
{
cout << "父类函数调用01" << endl;
}
int a;
};
class B :public A
{
public:
B()
{
a = 2;
}
void f()
{
cout << "子类函数调用" << endl;
}
int a;
};
void t1()
{
B p;
cout << "p.a=" << p.a << endl;//访问子类中的a
cout << "p.A::a=" << p.A::a << endl;//父类中的a
//从子类对象访问父类中的同名成员需要加作用域
p.f();
p.A::f();//子类访问父类中同名成员函数需要加作用域
//p.f(1)如果子类中出现和父类同名的成员函数,
//子类的同名成员会隐藏掉父类中所有同名成员函数
p.A::f(1);//如果想访问到父类中被隐藏的同名成员函数,需要加作用域
}
int main()
{
t1();
system("pause");
return 0;
}
继承同名静态成员的处理
静态成员和非静态成员出现同名,处理方式一致
访问子类同名成员直接访问即可
访问父类同名成员需要加作用域
#include<iostream>
#include<string>
using namespace std;
class A
{
public:
static void f()
{
cout << "父类静态函数调用" << endl;
}
static void f(int a)
{
cout << "父类静态有参函数调用" << endl;
}
static int a;
};
int A::a = 1;//类外初始化
class B :public A
{
public:
static void f()
{
cout << "子类静态函数调用" << endl;
}
static int a;
};
int B::a = 2;//类外初始化
void t1()
{
B p;
cout << endl<<"通过对象访问静态成员" << endl;
cout << "p.a=" << p.a << endl;//访问子类中的a
cout << "p.A::a=" << p.A::a << endl;//父类中的a
cout << endl<<"通过类名访问静态成员" << endl;
cout << "B::a=" << B::a << endl;
cout << "B::A::a=" << B::A::a << endl;//第一个::表示通过类名的方式访问数据
//第二个::表示访问父类作用域下的a
}
void t2()
{
//通过对象访问
cout << endl<<"通过对象访问静态成员函数" << endl;
B p;
p.f();
p.A::f();
//通过类名访问
cout << endl<<"通过类名访问静态成员函数" << endl;
B::f();
B::A::f();
cout << endl<<"通过类名访问父类同名静态有参成员函数" << endl;
B::A::f(1);
//子类出现和父类同名静态成员函数,也会隐藏父类中所有同名成员函数
//如果想访问父类中被隐藏同名成员,需要加作用域
}
int main()
{
t1();
t2();
system("pause");
return 0;
}
继承语法
C++允许一个类继承多个类
语法:
class 子类 : 继承方式 父类1,继承方式 父类2……
多继承可能会引发父类中有同名成员出现,需要加作用域区分
注意:加了final的类不能作为父类
class A final
{
}
class B :public A//错误,A类不能作为父类
{
}
#include<iostream>
#include<string>
using namespace std;
class A
{
public:
A()
{
a = 1;
}
int a;
};
class B
{
public:
B()
{
a = 2;
}
int a;
};
class C :public A, public B
{
public:
C()
{
c = 3;
d = 4;
}
int c;
int d;
};
void t1()
{
C p;
cout << "sizeof(p)=" << sizeof(p)<<endl;
cout << "p.A::a=" << p.A::a << endl;//父类中有同名成员要加作用域
cout << "p.B::a=" << p.B::a << endl;
}
int main()
{
t1();
system("pause");
return 0;
}
菱形继承问题及其解决方法
菱形继承概念:
两个派生类继承同一个基类,又有某个类同时继承者两个派生类。
这种继承被称为菱形继承,或者钻石继承。
菱形继承问题:
1.B继承了A的数据,C同样继承了A的数据,当D使用数据时,就会产生二义性。
2.D继承自A的数据继承了两份,其实我们应该清楚,这份数据我们只需要一份就可以。
利用虚继承解决菱形继承的问题
继承之前加上关键字virtual变为虚继承
A类称为虚基类(最大的类)
继承了两个指针,指针通过偏移量找到唯一的数据
#include<iostream>
#include<string>
using namespace std;
class A
{
public:
A()
{
a = 1;
}
int a;
};
class B :virtual public A
{
public:
};
class C :virtual public A
{
public:
};
class D :public B, public C
{
public:
};
void t1()
{
D p;
p.B::a = 2;
p.C::a = 3;//虚继承使数据只有一份。
//当菱形继承,两个父类拥有相同数据,需要加以作用域区分
cout << "p.B::a=" << p.B::a << endl;
cout << "p.C::a=" << p.C::a << endl;
//只要有一份就可以,菱形继承导致数据有两份,资源浪费
cout << "p.a=" << p.a << endl;
}
int main()
{
t1();
system("pause");
return 0;
}