欢迎加入QQ:498903810 一起交流、讨论知识,里面有大佬,也有小白,天下码农一家亲,大家一起讨论进步。
细说继承
感觉上一篇博客对于继承说的不够详细,所以我在这一篇再详细的说一下继承。
现在给大家详细说一下继承的方式:public、protected、private。
public (父类访问级别) | protected (父类访问级别) | private (父类访问级别) |
---|---|---|
public (继承方式) | public | protected |
protected (继承方式) | protected | protected |
private (继承方式) | private | private |
在来介绍以下单个类的访问控制:
public:修饰的成员变量方法,在类的内部类的外部都能使用。
protected:修饰的成员变量方法,在类的内部使用,在继承的子类中可以使用,不能在类的外部使用。
private:修饰的成员变量方法,只能在类的内部使用,不能在类的外部使用。
C++中的继承方式会影响子类的对外访问属性。
public继承:父类成员在子类中保持原有访问级别。
protected继承:父类中public成员会变成protected
父类中protected成员仍然为protected
父类中private成员仍然为private
private继承:父类成员在子类中变成private成员。
父类private成员在子类中仍然存在,但是却无法访问,无论那种方式继承,派生类(子类)都不能直接使用基类的私有成员。
继承主要影响父类的属性在子类的子类的是否可以访问。如果是public
继承,子类的子类(孙子类)仍然可以从子类里继承得到父类的属性,并且可以访问且类外也可以访问,如果是protected
继承那么子类外将不可以访问。但是仍然可以让孙子类去继承子类在孙子类内去使用,在孙子类外不能访问。如果是private
继承,那么子类里可以使用,但是子类的类外不能使用,且孙子类继承子类之后不能访问父类的属性和方法。
差不多就是这些了,继承方式影响的不仅仅是子类,还会对孙子类类有影响。
大多数继承都是public
继承
子类、父类、子类普通成员变量的构造析构顺序
构造顺序:父类构造—子类成员变量构造—子类构造
析构顺序:子类析构—子类成员变量析构—父类析构
代码:
#include <iostream>
using namespace std;
class member
{
public:
member()
{
cout << "普通类的构造函数" << endl;
}
~member()
{
cout << "普通类的析构函数" << endl;
}
};
class parent
{
public:
parent()
{
cout << "父类的构造函数" << endl;
}
~parent()
{
cout << "父类的析构函数" << endl;
}
};
class son: public parent
{
public:
son()
{
cout << "子类的构造函数" << endl;
}
~son()
{
cout << "子类的析构函数" << endl;
}
private:
member m;
};
int main()
{
son s1;
return 0;
}
运行结果:
父类的构造函数
普通类的构造函数
子类的构造函数
子类的析构函数
普通类的析构函数
父类的析构函数
继承中同名的成员函数、成员变量
1、重名的数据成员:不加域作用符,默认修改子类的成员变量。
2、重名的成员函数:不加域作用符,默认调用子类的成员变量。
如果想要调用父类的成员函数,需要加类的域作用符号。
例:Parent::date;
就可以访问父类的成员变量了。
#include <iostream>
using namespace std;
class Parent
{
public:
Parent()
{
date = 1;
}
void print()
{
cout << "parent date = " << date<< endl;
}
int date;
};
class Son:public Parent
{
public:
Son()
{
date = 0;
}
void print()
{
cout << "son date = "<< date << endl;
}
int date;
};
int main()
{
Son s;
s.date =10;
s.print();
return 0;
}
运行结果:
son date = 10
同名隐藏(重定义,继承关系中存在)
父类子类中有同名的函数(参数无所谓),子类继承父类后,用子类调用与父类的同名函数,父类的所有的同名函数都会隐藏,子类不能调用到父类的同名函数。程序会报错。
解决:加父类的域作用符;或者添加命名空间。
#include <iostream>
using namespace std;
class Parent
{
public:
Parent()
{
date = 1;
}
void print()
{
cout << "parent date = " << date<< endl;
}
void print(int a = 1)
{
cout << "paretn a = " << a << endl;
}
int date;
};
class Son:public Parent
{
public:
Son()
{
date = 0;
}
void print()
{
cout << "son date = "<< Parent::date << endl;
}
int date;
};
int main()
{
Son s;
s.date =10;
s.print(1);//会报错,同名隐藏
return 0;
}
运行结果:
程序不会运行成功,同名隐藏。解决方法,加类的域作用符。
赋值兼容性原则
类型兼容规则是指在需要基类对象的任何地方,都可使用公有派生类的对象来替代,通过公有继承,派生类得到了基类中除构造函数、析构函数之外的所有成员,这个公有派生类实际就好具备了基类的所有功能,凡是基类能解决的问题,公有派生类都可以解决,类型兼容性规则中所指的替代包括以下情况。
子类对象可以当作父类对象使用
子类对象可以直接复制给父类对象
子类对象可以直接初始化父类对象
父类指针可以直接指向子类对象
父类引用可以直接引用子类对象
在替代之后,派生类对象就可以作为基类的对象使用,但是只能使用从基类继承的成员,类型兼容规则是多态性的重要基础之一。
向上转换:派生类对象赋值给基类
向下转换:基类对象赋值给派生类(特殊情况使用)
规范:类名首字母大写; 变量必须小写; 函数如果拥有只读属性,加const。
虚继承和虚基类
虚继承:在继承定义中包含了virtual
关键字的继承关系。
虚基类:在虚继承体系中的通过virtual
继承而来的基类。
关键字:virtual
虚基类和普通基类的构造顺序:
构造顺序:虚基类—>普通基类
析构顺序:普通基类—>虚基类
- 什么是多重继承?
答:同时继承多个父类- 多重继承有什么?
答:菱形继承/钻石继承。- 什么是菱形继承/钻石继承?
答:多重继承的两个或多个父类具有相同的祖先类。- 菱形继承/钻石继承有什么危害?
答:因为多重继承的两个或多个父类具有相同的祖先类。所以会有完全相同的属性和方法。因此当前多重继承类有两份相同的属性和方法。使用时会出现冲突。- 如何解决菱形继承/钻石继承导致的冲突?
答:使用虚继承。- 什么是虚继承?
答:父类在继承具有相同的祖先类时,加上virtual
。