美文网首页C语言
继承的多种方式、显示调用父类构造函数、父子之间的同名函数、vir

继承的多种方式、显示调用父类构造函数、父子之间的同名函数、vir

作者: 凯恩_Kane | 来源:发表于2019-07-17 17:53 被阅读0次

.继承方式

继承方式位于定义子类的”:”后面,比如:

class Line : public Object //继承方式是public
{

};
继承方式默认为private

在C++中,继承方式共有3种:

public继承

-指父类的成员(变量和函数)访问级别,在子类中保持不变

private继承

-指父类的成员,在子类中变为private私有成员.

-也就是说子类无法访问父类的所有成员

protected继承

-指父类的public成员 ,在子类中变为protected保护成员,其它成员级别保持不变

如下图所示:

image

注意: protected****继承只针对子类有效

比如当父类是protected继承时,则子类的子类就无法访问父类的所有成员

一般而言,C++项目只用到public继承

.显示调用父类构造函数

当我们创建子类对象时,编译器会默认调用父类无参构造函数
若有子类对象,也会默认调用子类对象的无参构造函数。

比如以下代码:

#include <iostream>
using namespace std;

class A{
    
    public:
    
        A(void){
            cout << "A created" << endl;
        }
    
        
    
    protected:
    
        
};

class B : public A{
    public:
        
        B(int s){
            
            cout << "B created " << s << endl;
        }
    
};

int main(){
    
    B b(123);
    return 0;
}

编译运行:

A created
B created 123

也可以通过子类构造函数的初始化列表来显示调用

#include <iostream>
using namespace std;

class A{
    
    public:
    
        A(void){
            cout << "A created" << endl;
        }
    
        A(int a){
            cout << "A created " << a << endl;  
        }
    
        
    
    protected:
    
        
};

class B : public A{
    public:
        
        B(int s):A(s){
            
            cout << "B created " << s << endl;
        }
    
};

int main(){
    
    B b(123);
    return 0;
}

A created 123
B created 123

.父子间的同名成员和同名函数

子类可以定义父类中的同名成员和同名函数
子类中的成员变量和函数将会隐藏父类的同名成员变量和函数
父类中的同名成员变量和函数依然存在子类中
通过作用域分辨符(::)才可以访问父类中的同名成员变量和函数

#include <iostream>
using namespace std;

class A{
    
    public:
    
        A(void){
            count = 100;
            cout << "A created" << count << endl;
            
        }
    
        A(int a){
            cout << "A created " << a << endl;  
        }
    
        void add(int i){
            count += i;
            
            cout << "A的count = " << count << endl;
        }
    
        int getcount(){
            return count;
        }
    
    private:
    
        int count;  
        
};

class B : public A{
    public:
        
        B(){
            count = 1000;
            cout << "B created " << count << endl;
        }
    
        void add(int i,int j){
            count += i + j;
        }
    
        int getcount(){
            return count;
        }
    
    private:
        int count;
    
};

int main(){
    
    B b;
    //b.add(10); //该行会报错,由于子类有add函数,所以编译器会默认在子类里寻找add(int i);
    b.A::add(10);////该行正确,执行父类的成员函数
    b.add(2,3);
    
    cout << "B的Count= " << b.getcount() << endl;
    
    return 0;
}

A created100
B created 1000
A的count = 110
B的Count= 1005

从打印结果看到,父类和子类之间的作用域是不同的, 所以执行父类的同名成员变量和函数需要作用域分辨符(::)才行

.虚函数

实现多态性,通过指向子类的父类指针或引用,可以访问子类中同名覆盖成员函数

首先参考下面,没有虚函数的示例:

#include <iostream>
using namespace std;

class A{
    
    public:
    
        
        void add(){
            
            cout << "A add() " << endl;
        }
    
        
};

class B : public A{
    public:
        
        
        void add(){
            cout << "A add() " << endl;
        }   
        
};

void print(A *p){
    p -> add();
}

int main(){
    A a;
    B b;
    print(&a);
    print(&b);
    
    return 0;
}

A add()
A add()
SIZEOF Parent:1
SIZEOF Child:1

从结果看出,即使example函数的指针p指向了B b,也只能调用父类的add(),无法实现多态性.

所以C++引入了虚函数概念,根据指针指向的对象类型,来执行不同类的同名覆盖成员函数,实现不同的形态

定义: 在父类成员函数的返回值前面,通过virtual关键字声明,这样便能访问子类中的同名成员函数了

#include <iostream>
using namespace std;

class A{
    
    public:
    
    virtual void add();        //将父类的成员函数定为虚函数
    {
        cout<<"A add()"<<endl;
    } 

    
        
};

class B : public A{
    public:
            
        void add(){
            cout << "B add() " << endl;
        }   
        
};

 void print(A *p){
    p -> add();
}

int main(){
    A a;
    B b;
    print(&a);
    print(&b);
    cout<<"SIZEOF Parent:"<< sizeof(a)<<endl;
    cout<<"SIZEOF Child:"<< sizeof(b)<<endl; 
    
    return 0;
}

A add()
B add()
SIZEOF Parent:8
SIZEOF Child:8

.虚析构函数

-在使用基类指针指向派生类对象时用到

-通过基类析构函数可以删除派生类对象

#include <iostream>

using namespace std;

class Base
{
public:
     Base()
    {
        cout << "Base()" << endl;
    }

     virtual ~Base()
    {
        cout << "~Base()" << endl;
    }
};

class Derived : public Base
{
public:
     Derived()
    {
        cout << "Derived()" << endl;
    }

     ~Derived()
    {
        cout << "~Derived()" << endl;
    }
};

int main()
{
    Base* p = new Derived(); 
    // ...
    delete p;

    return 0;
}

运行打印:

Base()
Derived()
~Derived()
~Base()
可以发现,由于基类的析构函数是虚函数,所以我们delete基类指针时,派生类也跟着调用了析构函数,从而避免了内存泄漏,也能满足使用dynamic_cast强制转换了

一般而言,虚构造函数只有在继承下才会被使用,单个类是不会使用虚构函数的,因为虚函数表会产生额外的空间

注意:构造函数不能成为虚函数,因为虚函数表是在构造函数执行后才会进行初始化

欢迎扫码加入QQ群一起学习讨论。

相关文章

  • 继承的多种方式、显示调用父类构造函数、父子之间的同名函数、vir

    .继承方式 继承方式位于定义子类的”:”后面,比如: class Line : public Object ...

  • 继承中执行顺序讨论

    继承中,子父类的构造函数(构造函数不被继承)1.子类必须调用父类的构造函数(构造函数不被继承)(1)如果没有写调用...

  • JS寄生组合式继承

    JS的继承方式有很多种,最理想的继承方式是寄生组合式继承。组合继承(构造函数和原型的组合)会调用两次父类构造函数的...

  • java子类调用父类构造器函数

    子类 调用 父类的构造函数:(构造函数不会被继承,只是被子类调用而已) 1、子类所有的 构造函数 默认调用父类的无...

  • 面向对象继承的方式

    创建父类 原型链继承:将父类的实例作为子类的原型 借用构造函数继承:在子类型构造函数的内部调用父类的构造函数 组合...

  • Java面向对象

    1、子类实例化时会默认调用父类无参构造函数,如果父类没有无参构造函数,则需要子类构造函数显示调用父类有参构造函数 ...

  • js 继承

    构造函数继承 类式继承是在函数对象内调用父类的构造函数,使得自身获得父类的方法和属性。call和apply方法为类...

  • java中继承,子类是否继承父类的构造函数

    java中继承,子类是否继承父类的构造函数 java继承中子类是不会继承父类的构造函数的,只是必须调用(隐式或者显...

  • JS中call方法遇到的困惑

    简单说一下call方法调用父类构造函数。 在一个子构造函数中,你可以通过调用父构造函数的call方法来实现继承,类...

  • C++ 从入门到放弃 (Day-07)

    父类的构造函数 ◼ 子类的构造函数默认会调用父类的无参构造函数◼ 如果子类的构造函数显式地调用了父类的有参构造函数...

网友评论

    本文标题:继承的多种方式、显示调用父类构造函数、父子之间的同名函数、vir

    本文链接:https://www.haomeiwen.com/subject/rttclctx.html