继承方式位于定义子类的”:”后面,比如:
class Line : public Object //继承方式是public
{
};
继承方式默认为private
在C++中,继承方式共有3种:
public继承
-指父类的成员(变量和函数)访问级别,在子类中保持不变
private继承
-指父类的成员,在子类中变为private私有成员.
-也就是说子类无法访问父类的所有成员
protected继承
-指父类的public成员 ,在子类中变为protected保护成员,其它成员级别保持不变
如下图所示:
注意: protected继承只针对子类有效
比如当父类是protected继承时,则子类的子类就无法访问父类的所有成员
一般而言,C++项目只用到public继承
显示调用父类构造函数
比如以下代码:
class StrA
{
public:
StrA()
{
cout<<"StrA()"<<endl;
}
StrA(string s)
{
cout<<"StrA(string s):"<<s<<endl;
}
};
class StrB : public StrA
{
public:
StrB(string s)
{
cout<<"StrB(int i):"<<s<<endl;
}
};
int main()
{
StrB b("123");
return 0;
}
编译运行:
StrA() //父类无参构造函数
StrB(int i):123
也可以通过子类构造函数的初始化列表来显示调用
接下来,修改上面子类的StrB(string s)函数,通过初始化列表调用StrA(string s)父类构造函数
改为:
StrB(string s): StrA(s)
{
cout<<"StrB(int i):"<<s<<endl;
}
运行打印:
StrA(string s):123
StrB(int i):123
父子间的同名成员和同名函数
比如:
class Parent{
public:
int mval;
Parent()
{
mval=1000;
}
void add(int i)
{
mval+=i;
}
};
class Child : public Parent
{
public:
int mval;
Child()
{
mval=100;
}
void add(int i,int j)
{
mval+=i+j;
}
};
在main()函数执行:
Child c;
//c. add(10); //该行会报错,由于子类有add函数,所以编译器会默认在子类里寻找add(int i);
c.Parent::add(10); //该行正确,执行父类的成员函数
c.add(2,3);
cout<<"Child.mval="<<c.mval<<endl;
cout<<"Parent.mval="<<c.Parent::mval<<endl;
打印:
Child.mval=105
Parent.mval=1010
从打印结果看到,父类和子类之间的作用域是不同的, 所以执行父类的同名成员变量和函数需要作用域分辨符(::)才行
父子间的兼容
以上示例的Parent父类Child子类为例
其实是编译器是将子类对象退化为了父类对象, 从而能通过子类来赋值初始化父类
所以上述的父类对象(包括指针/引用)也只能访问父类中定义的成员.
如果父类对象想访问子类的成员,只能通过强制转换,将父类对象转为子类类型
示例1,通过C方式转换:
Child c;
Parent* p3=&c;
Child *c2 = (Child*)p3;
示例2,通过static_cast转换:
Child c;
Parent* p3=&c;
Child *c2 = (static_cast*)<Child*>(p3);
虚函数
实现多态性,通过指向子类的父类指针或引用,可以访问子类中同名覆盖成员函数
首先参考下面,没有虚函数的示例:
class Parent
{
int i;
public:
void example()
{
cout<<"class Parent"<<endl;
}
};
class Child : public Parent
{
int j;
public:
void example()
{
cout<<"class Child"<<endl;
}
};
void print(Parent* p)
{
p->example();
}
int main()
{
Parent t;
Child c;
print(&t);
print(&c);
cout<<"SIZEOF Parent:"<<sizeof(t)<<endl;
cout<<"SIZEOF Child:"<<sizeof(c)<<endl;
}
运行打印:
class Parent
class Parent
SIZEOF Parent:4
SIZEOF Child:8
从结果看出,即使example函数的指针p指向了Child c,也只能调用父类的example(),无法实现多态性.
所以C++引入了虚函数概念,根据指针指向的对象类型,来执行不同类的同名覆盖成员函数,实现不同的形态
定义: 在父类成员函数的返回值前面,通过virtual关键字声明,这样便能访问子类中的同名成员函数了
接下来将上个示例的父类成员函数example()改写为虚函数:
virtual void print() //将父类的成员函数定为虚函数
{
cout<<"class Parent"<<endl;
}
运行打印:
class Parent
class Child
SIZEOF Parent:8
SIZEOF Child:12
可以发现,父类和子类的长度都增加了4字节,这4个字节就是用来指向“虚函数表”的指针,编译器便会更据这个指针来执行不同类的虚函数,实现多态性.