2一、继承:
1.基本概念:
继承是在一个已经存在的类的基础上新建一个类,新建的类拥有已经存在的类的特性。主要体现的是代码复用的思想。
● 已经存在的类被称为“基类(Base Class)”或“父类”
● 新建的类被称为“派生类”或“子类(Sub Class)”
2.函数隐藏:派生类的函数与基类函数签名相同时,会将基类中的函数隐藏掉。
#include <iostream>
using namespace std;
//1.函数隐藏
class F{
private:
string name;
public:
void func();
};
void F::func(){
cout<<"我是基类"<<endl;
}
class S:public F{
private:
string name;
public:
void func();
};
void S::func() {
cout<<"我是派生类"<<endl;
}
int main(){
F f1;
f1.func();
S s1;
s1.func();//派生类的func函数将基类中的隐藏掉了
s1.F::func();//可以调用基类中的func函数
}
3.构造函数
C++中规定,派生类无法继承基类的构造函数,派生类的任意一个构造函数都必须直接或间接调用基类的任意一个构造函数。
①构造函数不能继承!子类只会调用父类的无参构造函数,如果父类构造函数重载之后,就无法自动调用到父类的无参构造函数,程序运行就会报错!
②基类中的私有变量,派生类可以继承到,但是如果没有接口不可以使用!
默认情况下,编译器会为每个类增加一个无参构造函数,同时会在派生类的无参构造函数中调用基类的无参构造函数。
1)透传构造:
#include <iostream>
using namespace std;
class Father
{
private:
string name;
public:
Father(string name):name(name){}
string get_name() const
{
return name;
}
};
class Son:public Father
{
public:
// 编译器自动添加的代码
// Son():Father(){}
Son():Father("张") // 透传构造
{
}
Son(string name):Father(name){} // 透传构造
};
int main()
{
Son s;
cout << s.get_name() << endl;
Son s2("王");
cout << s2.get_name() << endl;
return 0;
}
2)委托构造:某个类的构造函数可以调用这个类的其他构造函数。
3)继承构造:C++11的新特性!
4.继承后对象的创建与销毁
1)代码:
#include <iostream>
using namespace std;
/**
* @brief The Value class 作为其他类的变量使用
*/
class Value
{
private:
string name;
public:
Value(string name):name(name)
{
cout << name << "构造函数" << endl;
}
~Value()
{
cout << name << "析构函数" << endl;
}
};
class Father
{
public:
static Value s_value; // 静态成员变量
Value value = Value("Father的成员变量"); // 成员变量
Father()
{
cout << "Father的构造函数" << endl;
}
~Father()
{
cout << "Father的析构函数" << endl;
}
};
Value Father::s_value = Value("Father的静态成员变量");
class Son:public Father
{
public:
static Value s_value; // 静态成员变量
Value value = Value("Son的成员变量"); // 成员变量
Son()
{
cout << "Son的构造函数" << endl;
}
~Son()
{
cout << "Son的析构函数" << endl;
}
};
Value Son::s_value = Value("Son的静态成员变量");
int main()
{
cout << "主函数开始" << endl;
Son* s = new Son;
cout << "正在使用s中:调用s的各种功能" << endl;
delete s;
cout << "主函数结束" << endl;
return 0;
}
2)结果
3)对运行结果的解释说明:
构造初始化前,一定要先开辟成员变量的空间!!!关键点->也就是在构造初始化函数前开辟空间。
1.静态变量是属于类的!
2.基类与派生类的构造函数以及成员变量的开辟时间
3.基类和派生类的析构函数运行时间
5.多重继承:
1)重点就是菱形继承
虚继承底层原理与编译器相关,当Sofa类和Bed类使用virtual继承Furniture类时,Sofa类的对象和Bed类的对象都会多一个隐藏指针,这个指针指向了Furniture类的一个表——虚基类表,查询这个表可以找到Furniture的函数调用位置。
真正的虚继承定义是Sofa与SofaBed、Bed与SofaBed的继承关系,此时SofaBed对象就会拥有两个继承来的隐藏虚基类表指针,在SofaBed对象调用Furniture的相关函数时,通过隐藏成员指针查询的调用位置进行比对来避免二义性问题。
6.权限
类内 |
派生类 |
主函数 | |
public |
√ |
√ |
√ |
protected |
√ |
√ |
× |
private |
√ |
× |
× |
默认private
①公有继承
公有继承下,基类的private成员可以被派生类继承,但是无法直接访问。基类的protected和public成员继承到派生类仍然作为派生类的protected和public的成员(权限不变)。
②保护继承
保护继承下,基类的private成员可以被派生类继承,但是无法直接访问。基类的protected和public成员继承到派生类都变成派生类的protected成员。
③私有继承
私有继承下,基类的private成员可以被派生类继承,但是无法直接访问。基类的protected和public成员继承到派生类都变成派生类的private成员。