自学内容网 自学内容网

c++ - 继承


一、使用继承

//父类
class Parent
{
public:
protected:
int _a;
};

//子类
class Subclasses: public Parent
{
public:
protected:
int _b;
};

在这里插入图片描述

二、继承方式与限定访问

继承方式:

继承方式
公有public
保护protected
私有private

限定访问:

限定访问
公有public
保护protected
私有private

父类

class Parent
{
public:
int _a = 1;
protected:
int _b = 2;
private:
int _c = 3;
};

公有继承与限定访问

//公有继承
class Subclasses: public Parent
{
public:
void test01()
{
cout << _a << endl;//公有+公有 = 公有
cout << _b << endl;//公有+保护 = 保护
cout << _c << endl;//公有+私有 = 不可见(在子类中不可访问)
}
protected:
int _n;
}

在这里插入图片描述

保护继承与访问限定

//保护继承
class Subclasses : protected Parent
{
public:
void test01()
{
cout << _a << endl;//保护+公有 = 保护
cout << _b << endl;//保护+保护 = 保护
cout << _c << endl;//保护+私有 = 不可见(在子类中不可访问)
}
protected:
int _n;
};

在这里插入图片描述

私有继承与访问限定

//私有继承
class Subclasses : private Parent
{
public:
void test01()
{
cout << _a << endl;//私有+公有 = 私有
cout << _b << endl;//私有+保护 = 私有
cout << _c << endl;//保护+私有 = 不可见(在子类中不可访问)
}
protected:
int _n;
};

在这里插入图片描述

总结:
1、权限小的碰到权限大的---->权限变小。
2、私有成员被继承时在派生类中也不可见(指的是不可访问)。
3、保护限定在继承中起了关键作用,当父类被实例化时,保护成员在类外不可访问,被子类继承时子类也能够访问。

三、隐藏(重定义)

父类和子类的作用域不同,当子类和父类出现相同变量命名或者成员函数命名(函数名相同即可)相同时子类就会隐藏父类。

//父类
class Parent
{
public:
void test01()
{
cout << "class Parent" << endl;
}
protected:
int _a = 1;
int _b = 2;
};

//公有继承
class Subclasses: public Parent
{
public:
//隐藏了父类中的test01()
void test01()
{
cout << "class Subclasses: public Parent" << endl;
}
void test02()
{
//隐藏了父类的_a,使用子类_a = 10;
cout << _a << endl;
}
protected:
int _a = 10;
};

void test()
{
Subclasses s;
s.test02();
s.test01();
}

在这里插入图片描述

四、子类与父类之间的赋值转换

1、子类赋值给父类对象、指针、引用叫做切片或者叫切割。
2、父类赋给子类是不被允许的,但是可以强制类型转换,此时就有可能出现越界访问。
3、特殊语法规则:该类转换与普通变量不一样不会产生临时变量。
在这里插入图片描述
在这里插入图片描述

//父类
class Parent
{
public:
protected:
int _a = 1;
int _b = 2;
};

//公有继承
class Subclasses : public Parent
{
public:

protected:
int _c = 10;
};

void test()
{
//子类
Subclasses s;

//赋值给父类对象
Parent p1 = s;

//赋值给父类指针
Parent *p2 = &s;

//赋值给父类引用
Parent& p3 = s;


//强制类型转换
Parent *p4;
Subclasses* s1 = (Subclasses*)p4;
}

五、父类默认成员函数在子类中的初始化

1、构造函数
对父类:调用其构造函数。
当父类构造函数是默认构造时可以不用显示,如:

//父类
class Parent
{
public:
Parent()
{
cout << "class Parent" << endl;
}
protected:
int _a = 1;
int _b = 2;
};

//公有继承
class Subclasses : public Parent
{
public:
Subclasses()
{
cout << "class Subclasses : public Parent" << endl;
}
protected:
int _c = 10;
};

void test()
{
Subclasses s;
}

在这里插入图片描述
当父类构造函数不是默认无参构造时,就需要要初始化列表显示写出了,如:

//父类
class Parent
{
public:
Parent(int a,int b):_a(a),_b(b)
{
cout << "class Parent" << endl;
}
protected:
int _a = 1;
int _b = 2;
};

//公有继承
class Subclasses : public Parent
{
public:
//显示写出
Subclasses() :Parent(10, 10)
{
cout << "class Subclasses : public Parent" << endl;
}
protected:
int _c = 10;
};

void test()
{
Subclasses s;
}

在这里插入图片描述

2、拷贝构造
对父类:调用其拷贝构造
子类需要进行浅拷贝时不需要显示写出,编译器会自动调用父类拷贝构造。
子类需要进行深拷贝时需要显示写出,如:

//父类
class Parent
{
public:
Parent(){}
Parent(Parent&p)
{
cout << "Parent(Parent&p)" << endl;
}
protected:
int _a = 1;
int _b = 2;
};

//公有继承
class Subclasses : public Parent
{
public:
Subclasses() :Parent(){}
Subclasses(Subclasses& s):Parent(s)//用s赋值,传给父类时会切片处理
{
cout << "Subclasses(Subclasses& s)" << endl;
//深拷贝......
}
protected:
int *_c = new int[10];
};

void test()
{
Subclasses s1;
Subclasses s2(s1);
}

3、赋值运算符重载
对父类:调用其赋值运算符重载函数
子类需要进行浅拷贝时不需要显示写出,编译器会自动调用父类赋值运算符重载函数。
子类需要进行深拷贝时需要显示写出,如:

//公有继承
class Subclasses : public Parent
{
public:
Subclasses() :Parent() {}
Subclasses& operator=(Subclasses& s)
{
//因为子类的operator=和父类的operator=构成了隐藏关系,所以要指定类域
Parent::operator=(s);
cout << "Subclasses& operator=(Subclasses& s)" << endl;
//深拷贝.....
return s;
}
protected:
int* _c = new int[10];
};

void test()
{
Subclasses s1;
Subclasses s2;
s2 = s1;
}

在这里插入图片描述
4、析构函数
父类析构函数不像其他默认成员函数那样有时候需要显示调用,都是编译器进行隐式调用的,无需我们显示写出。
当子类没有资源清理时,无需写析构函数。
当子类有资源清理时,就跟平常一样写析构函数即可,无需显示调用父类析构函数,如:

class Parent
{
public:
Parent() {}
~Parent() 
{
cout << "~Parent()" << endl;
}
protected:
int _a = 1;
int _b = 2;
};
//公有继承
class Subclasses : public Parent
{
public:
Subclasses() :Parent() {}
~Subclasses()
{
cout << "~Subclasses()" << endl;
//释放内存
}
protected:
int* _c = new int[10];
};

void test()
{
Subclasses s1;
}

在这里插入图片描述
5、子类、父类的构造和析构的顺序
在这里插入图片描述
总结:构造:先父后子,析构:先子后父。

六、继承与友元

友元是不能被继承,就是你父亲的朋友不是你的朋友。

七、父类的静态成员变量

子类继承的静态成员变量和其他子类以及父类都是共用一个。
如:
进行计数:

class Parent
{
public:
Parent() { _d++; }
void test01() { cout << _d << endl; }
protected:
int _a = 1;
int _b = 2;
static int _d;
};
int Parent::_d = 0;
//公有继承
class Subclasses : public Parent
{
public:
Subclasses() :Parent() {}
void test01() { cout << _d << endl; }
protected:
int _c ;
};

void test()
{
//构建两个变量
Subclasses s1;//调用一个父类 _d++
Parent p;//调用一个父类 _d++
p.test01();//_d = 2
s1.test01();//_d = 2
}

在这里插入图片描述

八、多继承

当一个子类继承了多个父类时,叫多继承
如:

class Parent1
{
public:
Parent1() { cout << "Parent1()" << endl; }
protected:
int _a = 1;
int _b = 2;
};

class Parent2
{
public:
Parent2() { cout << "Parent2()" << endl; }
protected:
int _a = 1;
int _b = 2;
};

//公有继承
class Subclasses : public Parent1, public Parent2
{
public:
Subclasses() :Parent1(), Parent2() {}
protected:
int _c;
};

void test()
{
Subclasses s1;//调用一个父类 _d++
}

在这里插入图片描述
父类构造的顺序:按照定义时的顺序。
父类析构的顺序:与定义时的顺序相反。

菱形继承:
在这里插入图片描述
菱形继承造成的问题:
冗余和二义性。
如:

class A
{
public:
protected:
int _a = 0;
int _b = 0;
};

class B:public A
{
public:
protected:
int _c = 0;
};

class C :public A
{
public:
protected:
int _d = 0;
};

class D :public B,  public C
{
public:
void test() { cout << _a << endl }
protected:
int _e = 0;
};

在这里插入图片描述
在这里插入图片描述

_a,_b命名相同(二义性),在不同作用域下虽然指定作用域可以共存,但是它们的含义是一样的(冗余)。

解决菱形继承问题:
使用虚拟继承
关键字:virtual
在会出现菱形继承的类 :后加入关键字。
如:

class A
{
public:
protected:
int _a = 0;
int _b = 0;
};
class B: virtual public A
{
public:
protected:
int _c = 0;
};
class C : virtual public A
{
public:
protected:
int _d = 0;
};

class D :public B,  public C
{
public:
void test()
{
cout << _a << endl;
cout <<_b<<endl;
}
protected:
int _e = 0;
};

void test()
{
D d;
d.test();
}

在这里插入图片描述
可以正常使用_a,_b,并且只有一份。
虚拟继承的原理:
通过虚基表去实现:
这里是通过了B和C的两个指针,指向的一张表。这两个指针叫虚基表指针,这两个表叫虚基表。虚基表中存的偏移量。通过偏移量可以找到下面的A。
在这里插入图片描述


原文地址:https://blog.csdn.net/2302_79539362/article/details/140362834

免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!