概念及工方式
- 保持已有类的特性而构造新类的过程称为继承。
- 在已有类的基础上新增自己的特性而产生新类的过程称为派生。
- 被继承的已有类称为基类(或父类)。
- 派生出的新类称为派生类(或子类)
继承的目的
- 实现代码重用
- 派生的目的:当新的问题出现,原有程序无法解决(或不能完全解决)时,需要对原有程序进行改造
派生类的构造
- 派生类可以直接访问基类的保护数据成员
- 只以接口作沟通。即使基类与子类也不例外。这正是类能够发挥其生命力的原因所在。
- 在构造一个子类时,完成其基类部分的构造由基类的构造函数去做
继承的访问权限
- 派生类成员对基类成员的访问权限
- 通过派生类对象对基类成员的访问权限
- 公有继承
- 私有继承
- 保护继承
公有继承
- 基类的public和protected成员的访问属性在派生类中保持不变,但基类的private成员不可直接访问。
- 派生类中的成员函数可以直接访问基类中的public和protected成员,但不能直接访问基类的private成员。
- 通过派生类的对象只能访问基类的public成员。
私有继承
- 基类的public和protected成员都以private身份出现在派生类中,但基类的private成员不可直接访问。
- 派生类中的成员函数可以直接访问基类中的public和protected成员,但不能直接访问基类的private成员。
- 通过派生类的对象不能直接访问基类中的任何成员。
保护继承
- 基类的public和protected成员都以protected身份出现在派生类中,但基类的private成员不可直接访问。
- 派生类中的成员函数可以直接访问基类中的public和protected成员,但不能直接访问基类的private成员。
- 通过派生类的对象不能直接访问基类中的任何成员
默认的继承是私有
private 和protect的区别
- 在单个类中,protected和private没有什么区别。
- 但在继承关系中,基类的private成员不但对应用程序隐藏,
- 甚至对派生类也隐藏。而基类的保护成员则只对应用程序隐藏,而对派生类则毫不隐瞒。
#include<iostream>
using namespace std;
class Shop
{
public:
int m_a;
void saleDaliyGoods()
{
cout<<"卖日用品"<<endl;
return;
}
};
class Market:public Shop
{
public:
void saleFood()
{
m_a=10;
cout<<"食品"<<m_a<<endl;
return;
}
};
class SuperMarket:public Market
{
public:
void pay()
{
cout<<"代缴水电费"<<endl;
return;
}
};
int main(int argc,char **argv)
{
SuperMarket m;
m.saleDaliyGoods();
m.saleFood();
m.pay();
}
//结果为:
//卖日用品
//食品10
//代缴水费
#include<iostream>
using namespace std;
class Shop
{
protected:
int m_a;
public:
void saleDaliyGoods()
{
cout<<"卖日用品"<<endl;
return;
}
};
class Market:public Shop
{
public:
void saleFood()
{
m_a=10;
cout<<"食品"<<m_a<<endl;
return;
}
};
int main(int argc,char **argv)
{
Market m;
// m.m_a=10;
m.saleDaliyGoods();
m.saleFood();
}
//用protected ,则在Market中可以访问,但是在int main中,m.m_a=10;是错误的
#include<iostream>
using namespace std;
class Shop
{
public:
Shop()
{
cout<<"Shop construct"<<endl;
}
};
class Market:public Shop
{
public:
Market()
{
cout<<"Market construct"<<endl;
}
};
int main()
{
Market m;
}
//结果为:
//shop construct
//Market construct
#include<iostream>
using namespace std;
class Shop
{
int m_a;
public:
Shop(int a)
{
m_a=a;
cout<<"Shop construct"<<m_a<<endl;
}
};
class Market:public Shop
{
public:
Market():Shop(222)
{
cout<<"Market construct"<<endl;
}
};
int main()
{
Market m;
}
//结果为:
//Shop construct222
//Market construct
#include<iostream>
using namespace std;
class Shop
{
int m_a;
public:
Shop(int a=111)
{
m_a=a;
cout<<"Shop construct"<<m_a<<endl;
}
};
class Market:public Shop
{
public:
Market():Shop()
{
cout<<"Market construct"<<endl;
}
};
int main()
{
Market m;
}
//结果为:Shop construct111
//Market construct
#include<iostream>
using namespace std;
class Shop
{
int m_a;
public:
Shop(int a)
{
m_a=a;
cout<<"Shop construct"<<m_a<<endl;
}
Shop()
{
m_a=333;
cout<<"Shop construct"<<m_a<<endl;
}
};
class Market:public Shop
{
public:
Market():Shop()
{
cout<<"Market construct"<<endl;
}
};
int main()
{
Market m;
}
//结果为:
Shop construct333
//Market construct
#include<iostream>
using namespace std;
class Shop
{
int m_a;
public:
Shop(int a)//=111)
{
m_a=a;
cout<<"Shop construct"<<m_a<<endl;
}
/* Shop()
{
m_a=333;
}*/
~Shop()
{
cout<<"~~~~~~~Shop"<<m_a<<endl;
}
};
class Test
{
public:
Test()
{
cout<<"Test construct"<<endl;
}
~Test()
{
cout<<"~~~~~~Test"<<endl;
}
};
class Market:public Shop
{
Test m_t;
public:
Market():Shop(222)
{
cout<<"Market construct"<<endl;
}
~Market()
{
cout<<"~~~~~Market"<<endl;
}
};
int main()
{
Market m;
cout<<"=========="<<endl;
}
//结果为:
//Shop construct222
//Test construct
//Market construct
//============
//~~~~~~~~Market
//~~~~~~~~~Test
//~~~~~~~~~Shop
赋值兼容规则
- 派生类的对象可以赋值给基类对象。
- 派生类的对象可以初始化基类的引用。
- 派生类对象的地址可以赋给指向基类的指针。
#include<iostream>
using namespace std;
class B0
{
public:
void display()
{
cout<<"B0 display"<<endl;
}
};
class B1:public B0
{
public:
void display()
{
cout<<"B1 display"<<endl;
}
};
class D1:public B1
{
public:
void display()
{
cout<<"D1 display"<<endl;
}
};
int main()
{
B0 b0;b0.display();
B1 b1;b1.display();
// D1 d1;d1.display();
D1 b3;b3.B1::display();
}
//结果为:
//B0 display
//B1 display
//B1 display
重写虚函数,实现多态(多态)
- 多态是C++的重要概念,是面向对象设计理念的精华, 大型的C++软件项目和大型的系统实现中,多态是必不可少的,可以减轻系统升级、维护、调试的工作量和复杂度.
多态的条件
- C++多态是通过虚函数实现的,虚函数允许子类重新定义成员函数,而子类重新定义父类接口的做法称为覆盖或重写
- 子类需要公有继承于父类
- 定义父类的指针或引用,然后通过指针或引用去调用相应的虚函数
虚函数
- 成员函数之前加上 virtua
关键字之后,就是虚成员函数
判断子类的成员函数是否为虚函数
- 该函数是否与基类的虚函数相同的函数名
- 该函数是否与基类的虚函数有相同的参数个数及相同的对应参数类型
- 该函数是否与基类的虚函数有相同的返回值或者满足赋值兼容规则的指针、引用的返回值
多态与非多态的区别
- 多态与非多态的区别就是函数地址是早绑定还是晚绑定。如果函数的调用在编译期间就可以确定函数的调用地址,并生产代码,就是静态的也就是早绑定是非多态的。而如果函数的调用地址不能在编译期间确定,需要在运行时才确定,这就是晚绑定也称动态联编,是多态的
#include<iostream>
using namespace std;
class B0
{
public:
virtual void display()
{
cout<<"B0 display"<<endl;
}
};
class B1:public B0
{
public:
void display()
{
cout<<"B1 display"<<endl;
}
};
class D1:public B1
{
public:
void display()
{
cout<<"D1 display"<<endl;
}
};
int main()
{
B0 b0,*p0;
p0=&b0;
p0->display();
B1 b1;
p0=&b1;
p0->display();
D1 d1;
p0=&d1;
p0->display();
// D1 b3;b3.B1::display();
}
//结果为:
//B0 display
//B1 display
//D1 display
重载与重写的区别(重写重要)
- 重载overload:函数名相同,参数列表不同,重载只是在同类的内部存在,并且不能靠返回值来判断
- 重写overwrite:也称覆盖,子类重新定义父类中的同名函数。函数特征相同,单数具体实现不同,基类的函数要有关键字virtual,主要是在继承关系中出现。
重写函数
#include<iostream>
using namespace std;
class B0
{
public:
virtual void display()
{
cout<<"B0 display"<<endl;
}
};
class B1:public B0
{
/* public:
void display()
{
cout<<"B1 display"<<endl;
}*/
};
class D1:public B1
{
public:
void display()
{
cout<<"D1 display"<<endl;
}
};
int main()
{
B0 b0,*p0;
p0=&b0;
p0->display();
B1 b1;
p0=&b1;
p0->display();
D1 d1;
p0=&d1;
p0->display();
}
//结果为:
//B0 display
//B0 display
//D1 display
纯虚函数
#include<iostream>
using namespace std;
class B0
{ public:
virtual void display()=0;
};
class B1:public B0
{
public:
void display()
{
cout<<"B1 display"<<endl;
}
};
int main()
{
B0 *p0;//加上B0 b0有错
B1 b1;
p0=&b1;
p0->display();
}
B1 display
- 多继承(缺点:如果Father有一个id,Mother也有一个id,则多继承,Son会有两个id,二义性)
#include<iostream>
using namespace std;
class Father
{
public:
void money()
{
cout<<"有钱"<<endl;
}
};
class Mother
{
public:
void face()
{
cout<<"高挑,漂亮"<<endl;
}
};
class Son:public Father,public Mother
{
};
int main()
{
Son s;
s.money();
s.face();
}
//结果为:
//有钱
//高挑,漂亮
#include<iostream>
using namespace std;
class Person
{
public:
int id;
};
class Father:virtual public Person
{
public:
void money()
{
cout<<"有钱"<<endl;
}
};
class Mother:virtual public Person
{
public:
void face()
{
cout<<"高挑,漂亮"<<endl;
}
};
class Son:public Father,public Mother
{
};
int main()
{
Son s;
s.id=3;
Person *p=&s;
cout<<p->id<<endl;
}
//结果为3
继承顺序
- 任何虚拟基类的构造函数按照它们被继承的顺序构造
- 任何非虚拟基类的构造函数按照它们被继承的顺序构造;
- 任何成员对象的构造函数按照它们声明的顺序调用;
类自己的构造函数。
继承顺序
#include<iostream>
using namespace std;
class A
{
public:
A()
{
cout<<"A construct"<<endl;
}
~A()
{
cout<<"~~~~~~~A"<<endl;
}
};
class B
{
public:
B()
{
cout<<"B construct"<<endl;
}
~B()
{
cout<<"~~~~~~~B"<<endl;
}
};
class C
{
public:
C()
{
cout<<"C construct"<<endl;
}
~C()
{
cout<<"~~~~~~~C"<<endl;
}
};
class D:public A,public B,virtual public C
{
public:
D()
{
cout<<"D construct"<<endl;
}
~D()
{
cout<<"~~~~~~~D"<<endl;
}
};
int main()
{
D d;
cout<<"========="<<endl;
}
//结果为:
//C construct
//A construct
//B construct
//D construct
//=========
//~~~~~~~D
//~~~~~~~B
//~~~~~~~A
//~~~~~~~C