.继承方式
继承方式位于定义子类的”:”后面,比如:
class Line : public Object //继承方式是public
{
};
继承方式默认为private
在C++中,继承方式共有3种:
public继承
-指父类的成员(变量和函数)访问级别,在子类中保持不变
private继承
-指父类的成员,在子类中变为private私有成员.
-也就是说子类无法访问父类的所有成员
protected继承
-指父类的public成员 ,在子类中变为protected保护成员,其它成员级别保持不变
如下图所示:
注意: protected****继承只针对子类有效
比如当父类是protected继承时,则子类的子类就无法访问父类的所有成员
一般而言,C++项目只用到public继承
.显示调用父类构造函数
当我们创建子类对象时,编译器会默认调用父类无参构造函数
若有子类对象,也会默认调用子类对象的无参构造函数。
比如以下代码:
#include
using namespace std;
class A{
public:
A(void){
cout << "A created" << endl;
}
protected:
};
class B : public A{
public:
B(int s){
cout << "B created " << s << endl;
}
};
int main(){
B b(123);
return 0;
}
编译运行:
A created
B created 123
也可以通过子类构造函数的初始化列表来显示调用
#include
using namespace std;
class A{
public:
A(void){
cout << "A created" << endl;
}
A(int a){
cout << "A created " << a << endl;
}
protected:
};
class B : public A{
public:
B(int s):A(s){
cout << "B created " << s << endl;
}
};
int main(){
B b(123);
return 0;
}
A created 123
B created 123
.父子间的同名成员和同名函数
子类可以定义父类中的同名成员和同名函数
子类中的成员变量和函数将会隐藏父类的同名成员变量和函数
父类中的同名成员变量和函数依然存在子类中
通过作用域分辨符(::)才可以访问父类中的同名成员变量和函数
#include
using namespace std;
class A{
public:
A(void){
count = 100;
cout << "A created" << count << endl;
}
A(int a){
cout << "A created " << a << endl;
}
void add(int i){
count += i;
cout << "A的count = " << count << endl;
}
int getcount(){
return count;
}
private:
int count;
};
class B : public A{
public:
B(){
count = 1000;
cout << "B created " << count << endl;
}
void add(int i,int j){
count += i + j;
}
int getcount(){
return count;
}
private:
int count;
};
int main(){
B b;
//b.add(10); //该行会报错,由于子类有add函数,所以编译器会默认在子类里寻找add(int i);
b.A::add(10);////该行正确,执行父类的成员函数
b.add(2,3);
cout << "B的Count= " << b.getcount() << endl;
return 0;
}
A created100
B created 1000
A的count = 110
B的Count= 1005
从打印结果看到,父类和子类之间的作用域是不同的, 所以执行父类的同名成员变量和函数需要作用域分辨符(::)才行
.虚函数
实现多态性,通过指向子类的父类指针或引用,可以访问子类中同名覆盖成员函数
首先参考下面,没有虚函数的示例:
#include
using namespace std;
class A{
public:
void add(){
cout << "A add() " << endl;
}
};
class B : public A{
public:
void add(){
cout << "A add() " << endl;
}
};
void print(A *p){
p -> add();
}
int main(){
A a;
B b;
print(&a);
print(&b);
return 0;
}
A add()
A add()
SIZEOF Parent:1
SIZEOF Child:1
从结果看出,即使example函数的指针p指向了B b,也只能调用父类的add(),无法实现多态性.
所以C++引入了虚函数概念,根据指针指向的对象类型,来执行不同类的同名覆盖成员函数,实现不同的形态
定义: 在父类成员函数的返回值前面,通过virtual关键字声明,这样便能访问子类中的同名成员函数了
#include
using namespace std;
class A{
public:
virtual void add(); //将父类的成员函数定为虚函数
{
cout<<"A add()"< add();
}
int main(){
A a;
B b;
print(&a);
print(&b);
cout<<"SIZEOF Parent:"<< sizeof(a)<
A add()
B add()
SIZEOF Parent:8
SIZEOF Child:8
.虚析构函数
-在使用基类指针指向派生类对象时用到
-通过基类析构函数可以删除派生类对象
#include
using namespace std;
class Base
{
public:
Base()
{
cout << "Base()" << endl;
}
virtual ~Base()
{
cout << "~Base()" << endl;
}
};
class Derived : public Base
{
public:
Derived()
{
cout << "Derived()" << endl;
}
~Derived()
{
cout << "~Derived()" << endl;
}
};
int main()
{
Base* p = new Derived();
// ...
delete p;
return 0;
}
运行打印:
Base()
Derived()
~Derived()
~Base()
可以发现,由于基类的析构函数是虚函数,所以我们delete基类指针时,派生类也跟着调用了析构函数,从而避免了内存泄漏,也能满足使用dynamic_cast强制转换了
一般而言,虚构造函数只有在继承下才会被使用,单个类是不会使用虚构函数的,因为虚函数表会产生额外的空间
注意:构造函数不能成为虚函数,因为虚函数表是在构造函数执行后才会进行初始化
欢迎扫码加入QQ群一起学习讨论。