🎁个人主页:我们的五年
🔍系列专栏: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();
}
●在父类和子类中,只要两个函数的函数名相同就构成隐藏。
●在实际中,不建议在父类,子类写同名的函数。