凡科建站怎么做微网站广州市专业做网站
news/
2025/9/30 14:00:47/
文章来源:
凡科建站怎么做微网站,广州市专业做网站,下载什么网站做吃的,wordpress个人收款废话不多说直接上代码
class 派生类名:#xff3b;继承方式#xff3d; 基类名{ 派生类新增加的成员 };
继承方式限定了基类成员在派生类中的访问权限#xff0c;包括 public#xff08;公有的#xff09;、private#xff08;私有的#xff09;和 protected…废话不多说直接上代码
class 派生类名:继承方式 基类名{ 派生类新增加的成员 };
继承方式限定了基类成员在派生类中的访问权限包括 public公有的、private私有的和 protected受保护的。此项是可选项如果不写默认为 private成员变量和成员函数默认也是 private。 现在我们知道public、protected、private 三个关键字除了可以修饰类的成员还可以指定继承方式。
继承方式
不同的继承方式会影响基类成员在派生类中的访问权限。1) public继承方式
基类中所有 public 成员在派生类中为 public 属性基类中所有 protected 成员在派生类中为 protected 属性基类中所有 private 成员在派生类中不能使用。
2) protected继承方式
基类中的所有 public 成员在派生类中为 protected 属性基类中的所有 protected 成员在派生类中为 protected 属性基类中的所有 private 成员在派生类中不能使用。
3) private继承方式
基类中的所有 public 成员在派生类中均为 private 属性基类中的所有 protected 成员在派生类中均为 private 属性基类中的所有 private 成员在派生类中不能使用。通过上面的分析可以发现 1) 基类成员在派生类中的访问权限不得高于继承方式中指定的权限。例如当继承方式为 protected 时那么基类成员在派生类中的访问权限最高也为 protected高于 protected 的会降级为 protected 2) 基类中的 private 成员在派生类中始终不能使用不能在派生类的成员函数中访问或调用。 3) 如果希望基类的成员能够被派生类继承并且毫无障碍地使用那么这些成员只能声明为 public 或 protected只有那些不希望在派生类中使用的成员才声明为 private。 4) 如果希望基类的成员既不向外暴露不能通过对象访问还能在派生类中使用那么只能声明为 protected。注意我们这里说的是基类的 private 成员不能在派生类中使用并没有说基类的 private 成员不能被继承。实际上基类的 private 成员是能够被继承的并且成员变量会占用派生类对象的内存它只是在派生类中不可见导致无法使用罢了。
改变访问权限
使用 using 关键字可以改变基类成员在派生类中的访问权限例如将 public 改为 private、将 protected 改为 public。 注意using 只能改变基类中 public 和 protected 成员的访问权限不能改变 private 成员的访问权限因为基类中 private 成员在派生类中是不可见的根本不能使用所以基类中的 private 成员在派生类中无论如何都不能访问。
#includeiostream
using namespace std;//基类People
class People {
public:void show();
protected:char *m_name;int m_age;
};
void People::show() {cout m_name 的年龄是 m_age endl;
}//派生类Student
class Student : public People {
public:void learning();
public:using People::m_name; //将protected改为publicusing People::m_age; //将protected改为publicfloat m_score;
private:using People::show; //将public改为private
};
void Student::learning() {cout 我是 m_name 今年 m_age 岁这次考了 m_score 分 endl;
}int main() {Student stu;stu.m_name 小明;stu.m_age 16;stu.m_score 99.5f;stu.show(); //compile errorstu.learning();return 0;
}
代码中首先定义了基类 People它包含两个 protected 属性的成员变量和一个 public 属性的成员函数。定义 Student 类时采用 public 继承方式People 类中的成员在 Student 类中的访问权限默认是不变的。 不过我们使用 using 改变了它们的默认访问权限如代码第 21~25 行所示将 show() 函数修改为 private 属性的是降低访问权限将 name、age 变量修改为 public 属性的是提高访问权限。 因为 show() 函数是 private 属性的所以代码第 36 行会报错。把该行注释掉程序输出结果为 我是小明今年16岁这次考了99.5分
继承时的名字遮蔽问题
如果派生类中的成员包括成员变量和成员函数和基类中的成员重名那么就会遮蔽从基类继承过来的成员。所谓遮蔽就是在派生类中使用该成员包括在定义派生类时使用也包括通过派生类对象访问该成员时实际上使用的是派生类新增的成员而不是从基类继承来的。
基类和派生类的构造函数
类的构造函数不能被继承。因为即使继承了它的名字和派生类的名字也不一样不能成为派生类的构造函数。 在设计派生类时对继承过来的成员变量的初始化工作也要由派生类的构造函数完成但是大部分基类都有 private 属性的成员变量它们在派生类中无法访问更不能使用派生类的构造函数来初始化。 这种矛盾在C继承中是普遍存在的解决这个问题的思路是在派生类的构造函数中调用基类的构造函数。
Student::Student(char *name, int age, float score): People(name, age), m_score(score){ }
People(name, age)就是调用基类的构造函数并将 name 和 age 作为实参传递给它m_score(score)是派生类的参数初始化表它们之间以逗号,隔开。 也可以将基类构造函数的调用放在参数初始化表后面 Student::Student(char *name, int age, float score): m_score(score), People(name, age){ }
但是不管它们的顺序如何派生类构造函数总是先调用基类构造函数再执行其他代码包括参数初始化表以及函数体中的代码总体上看和下面的形式类似
Student::Student(char *name, int age, float score){ People(name, age); m_score score;
}
当然这段代码只是为了方便大家理解实际上这样写是错误的因为基类构造函数不会被继承不能当做普通的成员函数来调用。换句话说只能将基类构造函数的调用放在函数头部不能放在函数体中。 另外函数头部是对基类构造函数的调用而不是声明所以括号里的参数是实参它们不但可以是派生类构造函数参数列表中的参数还可以是局部变量、常量等例如
Student::Student(char *name, int age, float score): People(小明, 16), m_score(score){ }
构造函数的调用顺序
从上面的分析中可以看出基类构造函数总是被优先调用这说明创建派生类对象时会先调用基类构造函数再调用派生类构造函数如果继承关系有好几层的话例如
A -- B -- C
那么创建 C 类对象时构造函数的执行顺序为
A类构造函数 -- B类构造函数 -- C类构造函数
构造函数的调用顺序是按照继承的层次自顶向下、从基类再到派生类的。 还有一点要注意派生类构造函数中只能调用直接基类的构造函数不能调用间接基类的。以上面的 A、B、C 类为例C 是最终的派生类B 就是 C 的直接基类A 就是 C 的间接基类。 C 这样规定是有道理的因为我们在 C 中调用了 B 的构造函数B 又调用了 A 的构造函数相当于 C 间接地或者说隐式地调用了 A 的构造函数如果再在 C 中显式地调用 A 的构造函数那么 A 的构造函数就被调用了两次相应地初始化工作也做了两次这不仅是多余的还会浪费CPU时间以及内存毫无益处所以 C 禁止在 C 中显式地调用 A 的构造函数。
调用规则事实上通过派生类创建对象时必须要调用基类的构造函数这是语法规定。换句话说定义派生类构造函数时最好指明基类构造函数如果不指明就调用基类的默认构造函数如果没有默认构造函数那么编译失败。 基类和派生类的析构函数
和构造函数类似析构函数也不能被继承。与构造函数不同的是在派生类的析构函数中不用显式地调用基类的析构函数因为每个类只有一个析构函数编译器知道如何选择无需程序员干涉。 另外析构函数的执行顺序和构造函数的执行顺序也刚好相反
创建派生类对象时构造函数的执行顺序和继承顺序相同即先执行基类构造函数再执行派生类构造函数。而销毁派生类对象时析构函数的执行顺序和继承顺序相反即先执行派生类析构函数再执行基类析构函数。多继承
容易让代码逻辑复杂、思路混乱一直备受争议中小型项目中较少使用后来的 Java、C#、PHP 等干脆取消了多继承。 多继承的语法也很简单将多个基类用逗号隔开即可。例如已声明了类A、类B和类C那么可以这样来声明派生类D class D: public A, private B, protected C{ //类D新增加的成员 }
D 是多继承形式的派生类它以公有的方式继承 A 类以私有的方式继承 B 类以保护的方式继承 C 类。D 根据不同的继承方式获取 A、B、C 中的成员确定它们在派生类中的访问权限。
多继承下的构造函数
多继承形式下的构造函数和单继承形式基本相同只是要在派生类的构造函数中调用多个基类的构造函数。以上面的 A、B、C、D 类为例D 类构造函数的写法为
D(形参列表): A(实参列表), B(实参列表), C(实参列表){ //其他操作 }
基类构造函数的调用顺序和和它们在派生类构造函数中出现的顺序无关而是和声明派生类时基类出现的顺序相同。仍然以上面的 A、B、C、D 类为例即使将 D 类构造函数写作下面的形式
D(形参列表): B(实参列表), C(实参列表), A(实参列表){ //其他操作 }
那么也是先调用 A 类的构造函数再调用 B 类构造函数最后调用 C 类构造函数。 命名冲突当两个或多个基类中有同名的成员时如果直接访问该成员就会产生命名冲突编译器不知道使用哪个基类的成员。这个时候需要在成员名字前面加上类名和域解析符::以显式地指明到底使用哪个类的成员消除二义性。 虚继承
多继承是指从多个直接基类中产生派生类的能力多继承的派生类继承了所有父类的成员。尽管概念上非常简单但是多个基类的相互交织可能会带来错综复杂的设计问题命名冲突就是不可回避的一个。
类 A 派生出类 B 和类 C类 D 继承自类 B 和类 C这个时候类 A 中的成员变量和成员函数继承到类 D 中变成了两份一份来自 A--B--D 这条路径另一份来自 A--C--D 这条路径。 在一个派生类中保留间接基类的多份同名成员虽然可以在不同的成员变量中分别存放不同的数据但大多数情况下这是多余的
//间接基类A
class A{
protected:int m_a;
};//直接基类B
class B: public A{
protected:int m_b;
};//直接基类C
class C: public A{
protected:int m_c;
};//派生类D
class D: public B, public C{
public:void seta(int a){ m_a a; } //命名冲突
private:int m_d;
};
为了消除歧义我们可以在 m_a 的前面指明它具体来自哪个类
void seta(int a){ B::m_a a; }
虚继承
虚继承使得在派生类中只保留一份间接基类的成员。 在继承方式前面加上 virtual 关键字就是虚继承。
//间接基类A
class A{
protected:int m_a;
};//直接基类B
class B: virtual public A{ //虚继承
protected:int m_b;
};//直接基类C
class C: virtual public A{ //虚继承
protected:int m_c;
};//派生类D
class D: public B, public C{
public:void seta(int a){ m_a a; } //正确void setb(int b){ m_b b; } //正确void setc(int c){ m_c c; } //正确void setd(int d){ m_d d; } //正确
private:int m_d;
};int main(){D d;return 0;
}
虚继承的目的是让某个类做出声明承诺愿意共享它的基类。其中这个被共享的基类就称为虚基类Virtual Base Class本例中的 A 就是一个虚基类。在这种机制下不论虚基类在继承体系中出现了多少次在派生类中都只包含一份虚基类的成员。 我们会发现虚继承的一个不太直观的特征必须在虚派生的真实需求出现前就已经完成虚派生的操作。在上图中当定义 D 类时才出现了对虚派生的需求但是如果 B 类和 C 类不是从 A 类虚派生得到的那么 D 类还是会保留 A 类的两份成员。 换个角度讲虚派生只影响从指定了虚基类的派生类中进一步派生出来的类它不会影响派生类本身。 在实际开发中位于中间层次的基类将其继承声明为虚继承一般不会带来什么问题。通常情况下使用虚继承的类层次是由一个人或者一个项目组一次性设计完成的。对于一个独立开发的类来说很少需要基类中的某一个类是虚基类况且新类的开发者也无法改变已经存在的类体系。 使用多继承经常会出现二义性问题必须十分小心。上面的例子是简单的如果继承的层次再多一些关系更复杂一些程序员就很容易陷人迷魂阵程序的编写、调试和维护工作都会变得更加困难因此不提倡在程序中使用多继承
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/922903.shtml
如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!