【C++课程学习】:继承(上)(详细讲解)
继承是面向对象程序设计使代码可以复用的重要手段,它允许在原有类的基础上进行拓展,增加功能,形成新的类。继承体现了面向对象程序设计的层次结构。继承是类设计层级的复用。//基类(父类)private://派生类(子类)//子类拓展的内容。
🎁个人主页:我们的五年
🔍系列专栏:C++课程学习
🎉欢迎大家点赞👍评论📝收藏⭐文章
目录
一.继承的概念和定义
🎄继承的概念:
继承是面向对象程序设计使代码可以复用的重要手段,它允许在原有类的基础上进行拓展,增加功能,形成新的类。
继承体现了面向对象程序设计的层次结构。继承是类设计层级的复用。
🎄继承的定义:
//基类(父类)
class person {
private:
string _name;
};
//派生类(子类)
class student:public person
{
//子类拓展的内容
};
基本概念:
由🌷1.派生类(子类),🌷2.基类(父类),🌷3.继承方式(可省略),构成。
子类:子类也可叫做派生类,是在继承父类(基类)以后生成的新类。
父类:原来的基础类。
继承方式:以哪种方式进行继承,继承的方式有三种:public,protected,private。
当不写的时候:
1.派生类是class,那么继承方式就是private(私有继承)。
2.派生类是struct,继承方式就是public(公有继承)。
基本格式:
下面的student是派生类,继承方式是:public(共有继承),基类是person。
🎄继承基类成员访问方式的变化(九种):
⏰1.规律:基类的private(私有)都是不可见,其他的:在派生类的访问方式=min(在基类的访问方式,继承方式)。
public>protected>private。
例如,基类的public成员,以private继承,在基类的访问方式=min(public,private)=private。
⏰2.基类的private成员无论以哪种方式继承,在派生类中都是不可见的。这里的不可见是指,虽然在派生类中继承下来,但是在派生类里,还是在类外面都是不能访问。
⏰3.如果基类的成员想被子类访问,不想被类外访问,那么把基类的成员定义为protected就可以了。也就是说,protected是在继承才出现的,在其他的地方,protected和private基本差不多。
⏰4.当不写的时候:(实际中还是写出继承方式比较好)
1.派生类是class,那么继承方式就是private(私有继承)。
2.派生类是struct,继承方式就是public(公有继承)。
⏰5.在实际中,一般的继承方式都是public,因为其他两种继承,会把基类的访问方式缩小。这个子类去生成新的子类的时候,拓展性就不高了。
二.基类和派生类对象赋值转换
●派生类对象可以赋值给基类的对象 / 基类的指针 / 基类的引用。这里可以看成切片或者切隔,还是指向派生类的。
●基类对象不能赋值给派生类对象。
●基类的指针和引用可以强制类型转化赋值给派生类的指针或者引用。但是必须是基类的指针或者引用是指向派生类才是安全的。
class person
{
protected:
string _name; // 姓名
string _sex; // 性别
int _age; // 年龄
};
class student : public person
{
public:
int _No; // 学号
};
void Test()
{
student st;
// 1.子类对象可以赋值给父类对象/指针/引用
person p = st;
person* pp = &st;
person& rp = st;
//2.基类对象不能赋值给派生类对象
//sobj = p;
// 3.基类的指针可以通过强制类型转换赋值给派生类的指针
pp = &st;
student* ps1 = (student*)pp; // 这种情况转换时可以的。
ps1->_No = 10;
pp = &p;
student* ps2 = (student*)pp; // 这种情况转换时虽然可以,但是会存在越界访问的问题
ps2->_No = 10;
}
下面最后一种情况时,pp先取一个student的地址,然后再强制类型转换给一个student类型的ps1,然后通过ps1去访问_No,不会发生越界。如果先取的也是person类型的地址,就会发生越界。
我的理解是,C++允许子类的指针给父类的指针,上面不越界的情况,是原来他是属于student,除person外那块空间可能进行特殊处理,表示如果再次转换回student就不会报错。
void test()
{
student st;
st._No = 123;
person* pp = &st;
student* ps1 = (student*)pp;
cout << ps1->_No << endl;
}
三.继承中的作用域
目前我学过的域有:全局域,类域,局部域,命名空间域。
在同一域中:
●不能有相同的变量名,即使他们的类型不同。
●可以有同名函数存在,但是参数列表不同,他们构成重载。
在两个域中:
●可以有相同的变量名。
●可以有函数原型相同的函数。
●在父类和子类中,他们两个都是单独的作用域。
●在父类和子类中(一个函数在父类,一个函数在子类),可以有函数原型一样的函数,他们构成隐藏。也叫重定义。
🥊隐藏:
🥅隐藏的概念:
子类屏蔽对父类同名函数的访问,如果要访问,需要在函数前面写父类,表示在父类去找。
不然如果你想用父类的那个同名函数,如果不显示指定,子类的对象调用时,编译器只会在子类中找,不会因为不匹配,而去父类找,如果不匹配,直接编译不通过。
基类::基类成员 进行显示访问!
class A
{
public:
void fun()
{
cout << "func()" << endl;
}
};
class B : public A
{
public:
void fun(int i)
{
A::fun();
cout << "func(int i)->" << i << endl;
}
};
void test()
{
B b;
b.fun(); //没有指定类域,编译器只会在子类中找,不匹配直接编译出错
b.A::fun();
}
●在父类和子类中,只要两个函数的函数名相同就构成隐藏。
●在实际中,不建议在父类,子类写同名的函数。
开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!
更多推荐
所有评论(0)