,在编译阶段就确定好是被谁调用,所以他只认哪个指针指向自己,这里是Animal指针指向,所以他就调用Animal里面的,普通函数是父类为子类提供的“强制实现”,也就是只要是父类指针调用普通函数,那就是父类的普通函数...而虚函数的作用,主要是为了让父类指针可以调用子类的函数,这种是在运行时才决定调用哪个函数 1、虚函数: C++的虚函数主要作用是“运行时多态”,父类中提供虚函数的实现,为子类提供默认的函数实现。...子类可以重写父类的虚函数实现子类的特殊化。 2、纯虚函数: C++中包含纯虚函数的类,被称为是“抽象类”。抽象类不能使用new出对象,只有实现了这个纯虚函数的子类才能new出对象。 ...3、普通函数: 普通函数是静态编译的,没有运行时多态,只会根据指针或引用的“字面值”类对象,调用自己的普通函数。 普通函数是父类为子类提供的“强制实现”。 ...因此,在继承关系中,子类不应该重写父类的普通函数,因为函数的调用至于类对象的字面值有关。 参考链接
一、不能自动继承的成员函数 构造函数(包括拷贝构造函数) 析构函数 =运算符 二、继承与构造函数 基类的构造函数不被继承,派生类中需要声明自己的构造函数。...声明构造函数时,只需要对本类中新增成员进行初始化,对继承来的基类成员的初始化调用基类构造函数完成(如果没有给出则默认调用默认构造函数)。...从输出可以看出: 派生类对象的构造次序: 先调用基类对象成员的构造函数,接着是基类的构造函数,然后是派生类的对象成员的构造函数,最后是派生类自身的构造函数。...初始化列表参数多个且其中有调用基类构造函数时,先执行基类构造函数(从最远的开始,如果多重继承则按继承的顺序);其他对象成员若不止一个,则按定义的顺序构造,与初始化列表顺序无关。...四、派生类到基类的转换 当派生类以public方式继承基类时,编译器可自动执行的转换(向上转型 upcasting 安全转换) 派生类对象指针自动转化为基类对象指针 派生类对象引用自动转化为基类对象引用
大家好,又见面了,我是全栈君 测试源代码: //測试派生类的构造函数的调用顺序何时调用 //Fedora20 gcc version=4.8.2 #include using namespace..."<<endl; A *a2=new A; //仅仅有在new 一个对象的时候才会调用基类的构造函数 cout调用基类的构造函数"<<endl; A *a3=&a; B b; } 输出为: 能够看到,在创建派生类的对象的时候,首先调用的是基类中的构造函数,然后才是调用派生类自己的构造函数...而在析构的时候,顺序则刚好相反,先调用派生类的析构函数,然后才是调用基类的构造函数。这是由于对象创建时候对象存放在堆栈中的原因。(new 的对象尽管是存在堆中,可是在堆栈中依旧存放其堆中的地址,因此。...析构的时候也是一样) 那么,创建其对象的数组时:A a[2],是否会调用其构造函数呢。这是肯定的。
static void main(String[] args) { A a = new A(); B b = new B(); } } 问题:为什么创建A对象的时候父类会调用子类方法...但是:创建B对象父类会调用父类的方法? 答案: 当子类被加载到内存方法区后,会继续加载父类到内存中。...如果,子类重写了父类的方法,子类的方法引用会指向子类的方法,否则子类的方法引用会指向父类的方法引用。 如果子类重载了父类方法,则子类重载方法引用还指向子类方法。...如果子类方法没有重写也没有重载父类方法,则方法引用会指向父类方法。 当子类对象创建时,会先行调用父类的构造方法(构造方法也是方法),虚拟机会在子类方法区寻找该方法并运行。...其结果是当编译的时候,父类构造方法调用的方法的参数已经强制转换为符合父类方法的参数了。 上边代码在编译前已经转换为下面这个样子的了。
基类的成员函数可以分为两类: 虚函数,希望派生类进行覆盖的函数,任何构造函数之外的非静态函数都可以是虚函数。关键字 virtual只能出现在类内部的声明语句之前而不能用于类外部的函数定义。...派生类应该遵循基类的接口,通过调用基类的构造函数来初始化那些从基类中继承而来的成员。派生类的初始化过程大致为:基类初始化——>基类构造函数体——>派生类初始化——>派生类构造函数体。...而对于非虚函数的调用是在编译时进行绑定。类似的,通过对象进行的函数(虚函数或非虚函数)调用也在编译时绑定。 一旦某个函数被声明为虚函数,则在所有派生类中它都是虚函数。...当基类构造函数具有默认实参时,实参不会被继承,而是派生类会获得多个继承的构造函数,每个构造函数分别省略掉一个含有默认实参的形参。...派生类定义的构造函数与基类的构造函数具有相同的形参列表时,则该构造函数不会被继承,派生类中使用的是自己定义的相应函数。 默认、拷贝和移动构造函数不会被继承,这些构造函数按照正常规则被合成。
三、构造函数的初始化顺序 构造基类的顺序与派生列表中基类的出现顺序有关,而与构造函数初始化列表中基类的初始化顺序无关 派生类构造自己之前同样需要构造基类对象。...using从继承基类的构造函数的概念 在C++11标准中,允许派生类从它的一个或几个基类中继承构造函数。...使用合成版本 如果派生类没有定义自己的拷贝/赋值构造函数和赋值运算符,那么在执行这些操作时将会自动调用基类的拷贝/赋值构造函数和赋值运算符 七、基类与派生类的类型转换 与单一继承原理一致,可以将一个派生类赋值给一个基类...,派生类的作用域嵌套在直接基类或间接基类的作用域中,也就是说当我们查找一个数据成员/方法时,在派生类中不存在,那么就继续向基类中进行查找,如果查找到了就进行使用 多重继承下派生类的作用域嵌套在所有的基类或间接基类的作用域中...二义性与二义性的解决 当同一个数据成员/函数的名称在不同的基类中出现时,程序不会出现错误(编译器允许定义)。
Must define an explicit constructor 这个错误是很多开发者经常遇到的错误,错误原因就是找不到超类中的默认构造函数。...编译器错误是因为默认的super()无参的构造函数是没有定义的。在Java中,如果一个类没有定义构造函数,编译器会自动插入一个默认的无参的构造函数。...上一小节,我们知道,如果子类的构造函数中,没有显示的调用父类的构造函数,那么,编译器就会插入super(),也就是自动调用无参的构造函数。但是此时,父类没有无参的构造函数,所以就会报错了。...解决这个问题很简单,我们可以给父类插入一个无参的构造函数,或者在子类构造函数中显示的调用的父类有参构造函数。 在子类的构造函数中显示的调用父类的构造函数 下面的代码是正确的。 ?...有一个原因就是,如果我们给所有的类都自动实现一个无参的构造函数,就可能出现问题,会打破类的设计原则。
子对象 Panda::Panda() : Endangered(Endagered::critical) { } 其中基类的构造顺序与派生列表中基类的出现顺序保持一致,而与派生类构造函数初始值列表中基类的顺序无关...// D2一旦定义了它自己的构造函数, 则必须出现 }; 1.3 析构函数与多重继承 派生类的析构函数只负责清除派生类本身分配的资源,派生类的成员以及基类都是自动销毁的。...析构函数的调用顺序正好与构造函数相反,在上面的例子中析构函数的调用函数是: ~Panda ~Endangered ~Bear ~ZooAnimal 1.4 多重继承的派生类的拷贝与移动操作 与只有一个基类的继承一样...构造函数与虚继承 在虚派生中,虚基类是由最低层的派生类初始化的。以我们的程序为例,当创建Panda对象时,由Panda的构造函数独自控制ZooAnimal的初始化过程。...如果ZooAnimal没有默认构造函数,那么代码将发生错误。 虚基类总是先于非虚基类构造,与它们在继承体系中的次序和位置无关。
,对内置类型不做处理,对自定义类型调用它的默认构造函数,规则和以前一样 派生类里面,把父类成员当做一个整体 派生类的构造函数必须调用基类的构造函数初始化基类的那一部分成员。...,父类的调用父类构造函数初始化 成员变量的初始化顺序是根据它们在类定义中出现的顺序,而不是初始化列表中的顺序。...因此,基类的构造函数总是首先被调用,再是派生类中定义的成员变量 派生类的拷贝构造函数必须调用基类的拷贝构造完成基类的拷贝初始化,一般情况下默认生成的就够用,如果涉及到深拷贝,就需要自己显示实现 Student...这样的设计可以防止基类成员被重复释放或者提前释放,从而导致潜在的错误和资源泄漏 派生类对象初始化:先调用基类构造再调派生类构造 派生类对象析构清理:先调用派生类析构再调基类的析构。...因此,无论是在基类还是派生类中访问静态成员,访问的都是同一个数据。在设计类层次结构时,这一点非常重要,因为静态成员的行为可能会影响整个类族
而当作用于构造函数时,using 声明语句将令编译器生成代码。对于基类的每个构造函数,编译器都在派生类中生成一个形参列表完全相当的构造函数。...,派生类构造函数会隐式调用基类默认构造函数,这由编译器实现,不需编写调用代码; 如果基类没有默认构造函数,即基类提供了重载的构造函数,则派生类构造函数通过初始化列表来调用基类构造函数,这属于显式调用。...这种方式是必需的,否则编译器会试图调用基类默认构造函数,而基类并无默认构造函数,编译会出错; 在派生类构造函数中,使用 ::Base() 形式显示调用基类构造函数。...如果基类包含重载的构造函数,需要在实例化时给它提供实参,则创建派生类对象时,可以使用初始化列表,并通过派生类的构造函数调用合适的基类构造函数。...例如,基类的公有成员遇到私有继承时,就变成派生类中的私有成员;基类的保护成员遇到公有继承时,就变成派生类中的保护成员;基类的私有成员派生类不可见。
而对于类中的自定义类型,它们会自动调用的构造和析构函数,如果是别的类的自定义类型,则会到它们自己的类中去调用它们的构造和析构函数。在多态中,基类先构造,然后再是派生类构造。...这样做的好处是,如果有人在类中调用了这些被私有化的函数,或者使用友元,那么会在连接期出现错误,而并非编译期的错误。如果是发生在连接期的错误,这种错误很难侦测出来!...() { Corgi co; return 0; } 分析代码: 代码中,用派生类创建了一个派生类的对象,在构造函数被调用的时候,会先去构造基类的成分,然后才会去构造派生类的从成分,这就意味着,会先去调用基类的构造函数...基类的构造函数最后会去执行count_Dog函数,问题就出现在这里,上面说了,构造函数构造期间,基类的virtual函数不会下降到派生类中,也就是说即使我们创建的对象属于派生类的,但是在调用基类的构造函数期间...做法就是在派生类中的拷贝构造函数和赋值重载中调用基类的拷贝构造和赋值函数。
基类private成员在派生类中是不能被访问,如果基类成员不想在类外直接被访问,但需要在派生类中能访问,就定义为protected。可以看出保护成员限定符是因继承才出现的。 3....派生类的构造函数必须调用基类的构造函数初始化基类的那一部分成员。如果基类没有默认的构造函数,则必须在派生类构造函数的初始化列表阶段显示调用。...在子类的初始化列表中显示定义_name的方式: 2. 派生类的拷贝构造函数必须调用基类的拷贝构造完成基类的拷贝初始化。...这里的赋值运算符重载会出现错误: 在vs2022上抛异常,在vs2019上面会出现上图的东西,vs2019上调试会抛异常栈溢出,这里的问题就是出现隐藏,子类和父类函数名相同,想调父类调不到,优先调用自己...因为这样才能保证派生类对象先清理派生类成员再清理基类成员的顺序。 5. 派生类对象初始化先调用基类构造再调派生类构造。 6. 派生类对象析构清理先调用派生类析构再调基类的析构。 7.
搜寻匹配 catch语句过程中,寻找的是第一个与异常匹配的 catch语句,是按照其出现的顺序逐一进行匹配的,当程序使用具有继承关系的多个异常时,要注意令派生类异常的处理代码出现在基类异常的处理代码之前...基类的构造顺序与派生类列表中基类的出现顺序保持一致,而与派生类构造函数初始值列表中基类的顺序无关。...在 C++11新标准中,允许派生类从它的一个或几个基类中继承构造函数,但是如果从多个基类中继承了相同的构造函数(即形参列表完全相同),则程序将产生错误。...自定义的拷贝/赋值构造函数和赋值运算符都需要显式调用基类的相应成员来完成派生类对象的拷贝、移动和赋值操作。只有当派生类使用的是合成版本的函数时,才会自动对齐基类部分执行相应操作。...含有虚基类的对象的构造顺序与一般的顺序稍有区别:首先使用提供给最低层派生类构造函数的初始值初始化该对象的虚基类子部分,接下来按照直接基类在派生列表中出现的次序依次对其进行初始化。
常见问题与易错点访问权限:派生类可能无法访问基类中的私有成员,导致误解。记住,只有公有和保护成员才能被继承。构造函数与析构函数:基类的构造函数和析构函数不会自动被调用,需要显式调用或使用初始化列表。...在派生类构造函数中,使用初始化列表显式调用基类的构造函数。多重继承时考虑菱形问题,适时使用virtual关键字。...在C++中,主要通过虚函数实现多态,使得派生类可以根据自身情况重写基类中的虚函数。...常见问题与易错点忘记使用virtual关键字:如果基类中的函数没有声明为虚函数,派生类即使重写了该函数,也无法实现动态绑定。切片问题:当将派生类对象赋值给基类对象时,派生类特有的部分会被“切片”掉。...空指针调用虚函数:对空指针调用虚函数会导致运行时错误。如何避免确保需要被重写的函数声明为虚函数。使用引用或指针处理基类和派生类的关系,避免切片问题。在调用虚函数前检查指针是否为空。
前者基类通常将其定义为虚函数virtual,当我们使用指针或者引用调用虚函数时,该调用将被动态绑定 任何构造函数之外的非静态函数都可以是虚函数 如果基类把一个函数声明成虚函数,那么该函数在派生类中隐式地也是虚函数...当我们delete一个动态分配的对象的指针时将执行析构函数,如果该指针指向继承体系中的某个类型,那么可能出现指针的静态类型与被删除对象的动态类型不符合的情况。...、赋值或者销毁操作 如果在基类中有一个不可访问或者删掉的析构函数,则派生类中合成的默认和拷贝构造函数将是被删除的,原因是编译器无法销毁掉派生类的基类部分 当我们使用=default请求一个移动操作时,如果基类中的对应操作是删除或者不可访问的...在构造函数和析构函数中调用虚函数 派生类对象的基类部分首先被构造,然后再构造派生类部分。对象销毁的顺序正好相反,派生类析构函数首先执行,然后是基类的析构函数。...当执行基类的构造函数时,该对象的派生类部分是未被初始化的状态;当执行基类的析构函数时,派生类部分已经被销毁了。
图4-8 派生类构造函数调用顺序 4.2.10 派生类构造函数使用中应注意的问题 派生类构造函数的定义中可以省略对基类构造函数的调用,其条件是在基类中必须有缺省的构造函数或者根本没有定义任何构造函数(编译器会自动生成缺省构造函数...图4-12 多继承构造函数调用顺序 4.3 二义性问题 原因:在多继承情况下,造成的对基类中某个成员的访问出现的不唯一的情况 4.3.1 成员函数二义性 ?...,则对该基类中说明的成员进行访问时,可能会出现二义性 4.3.2 成员变量二义性 ?...图4-16 虚基类与非虚基类存储结构 4.4.2 虚基类的构造函数 派生类中只有一个虚基类子对象 虚基类构造函数必须只被调用一次,目的是要保证虚基类子对象只被初始化一次 最派生类:继承结构中建立对象时所指定的类...虚基类子对象由最派生类的构造函数通过调用虚基类的构造函数进行初始化 在一个成员初始化列表中出现对虚基类和对非虚基类构造函数的调用时,虚基类的构造函数先于非虚基类的构造函数的执行 最派生类的构造函数的成员初始化列表中必须给出对虚基类的构造函数的调用
基类private成员在派生类中是不能被访问,如果基类成员不想在类外直接被访问,但需要在 派生类中能访问,就定义为protected。可以看出保护成员限定符是因继承才出现的。...void Test() B b; b.fun(); }; 上面这个调用的哪个fun呢?这里就不卖关子了,这里会报错。 这里直接会报编译错误,如果我们想调用A类中的函数怎么办呢?...析构函数 对于析构函数来说,首先我们要知道的是,在我们调用构造函数的时候,先初始化的是基类的成员,所以应该是基类成员先初始化,然后再初始化派生类自身的成员,所以这里应该是基类的成员先入栈,派生类再入栈,...我们还讨论了继承中的作用域问题以及派生类中的默认成员函数,包括构造函数、拷贝构造函数、赋值拷贝函数和析构函数。 特别地,我们重点分析了析构函数在多态性中的作用。...通过将基类的析构函数声明为虚函数,确保在基类指针指向派生类对象时,能够正确调用派生类的析构函数,从而避免资源泄露和内存管理问题。
一、继承中的构造函数 根据构造函数的执行流程我们知道: 派生类定义时,先执行基类的构造函数,再执行派生类的构造函数 拷贝构造函数与上面是相同的原理 二、继承中的析构函数 根据析构函数的执行流程我们知道:...派生类释放时,先执行派生类的析构函数,再执行基类的析构函数 二、继承中被删除的函数的语法 基类或派生类可以将其构造函数或者拷贝控制成员定义为删除的。...当我们使用=default请求一个移动操作时,如果基类中的对应操作是删除的或不可访问的,那么派生类中该函数是被删除的,原因是派生类对象的基类部分不可移动。...} }; 五、特别注意:在构造函数和析构函数中调用虚函数 根据构造函数,析构函数我们知道: 派生类构造时,先构造基类部分,然后再构造派生类部分 派生类析构时,先析构派生类部分,然后再析构基类部分 因此...: 在基类构造函数执行的时候,派生类的部分是未定义状态 在基类析构函数执行的时候,派生类的部分已经被释放了 所以在基类的构造函数或析构函数中调用虚函数是不建议的,因为: 虚函数在执行的时候可能会调用到属于派生类的成员
当派生类中定义与父类同名的成员时,派生类将屏蔽对基类该成员的直接访问,称这种情况为隐藏。而派生类中的同名成员是对基类成员的重写/重定义。...fun函数并不构成重载,因为他们在不同的作用域,他们是隐藏关系 四、派生类的默认成员函数 1.构造函数 派生类构造函数必须调用基类的构造函数初始化基类那一部分成员,如果基类没有默认构造函数,派生类就必须在初始化列表处显示的调用基类构造函数...派生类对象初始化时,会先调用基类构造函数,再调用派生类构造函数。 2.拷贝构造 必须调用基类的拷贝构造完成基类部分的拷贝构造。...4.析构函数 派生类额析构函数会在调用结束后自动调用基类的析构函数清理基类成员,确保先清理派生类的成员再清理基类的成员的析构顺序。 派生类对象析构先调用派生类析构函数再调用基类析构函数。...3.菱形继承 由于C++支持多继承,因此可能会出现菱形继承(一个派生类继承的多个基类拥有共同的基类)的情况。
领取专属 10元无门槛券
手把手带您无忧上云