C++ 继承 | 无关风月,我题序等你回~
Cobb 767 0

成员对象的构造和析构

class Date
{
public:
    Date(int y, int m, int d)  // Date date(1990, 1, 1); Date date;
    {
        cout << "Date(int, int, int)" << endl;
        this->year_ = y;
        this->month_ = m;
        this->day_ = d; // 嗯呐
    }
    ~Date()
    {
        cout << "~Date()" << endl;
    }
private:
    int year_;
    int month_;
    int day_;
};

class Book
{
public:
    // “Date”: 没有合适的默认构造函数可用 <= 因为你就没有指定date_对象的构造(初始化)方式
    // 构造函数的初始化列表 => 专门给成员变量指定初始化值的
    // 推荐把成员变量的初始化都写在 => 构造函数的初始化列表中
    Book(string name = "", int amount = 0, double price = 0.0,
        int y = 0, int m = 0, int d = 0)
        : name_(name)
        , amount_(amount)   // int amount_ = amount;
        , price_(price)
        , date_(y, m, d)    // Date date_(y,m,d);
    {
        // this
        // name_(name) => string name_(name);
        // 能进来构造函数的函数体,成员变量相当于都已经初始化过了,这里都是赋值操作
        cout << "Book(string, int, double)" << endl;

        // 不再这样初始化了
        //this->name_ = name; // string name_;   name_ = name;
        //this->amount_ = amount; // int amount_;  amount_ = amount;
        //this->price_ = price; // double price_; price_ = prioce;
    }
    ~Book()
    {
        cout << "~Book()" << endl;
    }
private:
    string name_;
    int amount_;
    double price_;
    Date date_;     // 成员对象   怎么给成员对象指定初始化方式
};
int main()
{
    // 一个类如果有成员对象
    // 构造过程:成员对象的构造,当前类的构造
    // 析构过程:当前类的析构,成员对象的析构
    Book book("精通C+_+", 20, 50.0, 2020, 1, 1);
}

初始化列表初始化的顺序和定义有关

class Test
{
public:
    Test(int data = 100) :b(data), a(b) {}
    void Show() { cout << a << " " << b << endl; }
private:
    int a;
    int b;
};
int main()
{
    Test t; // 0xcccccccc 0xcccccccc
    t.Show();
}

两个必须必须要初始化的类型

class Test
{
public:
    Test(int data = 100)
        : a(data)
        , b(data)
    {
    }
    void Show() { cout << a << " " << b << endl; }
private:
    const int a;
    int& b;
};

int main()
{
    Test t;
    t.Show();
}

继承的级别问题

问题:什么是继承? 类和类的关系主要有两种: 1、继承 a kind of... 一种的关系 2、组合 a part of... 一部分的关系 95%都是组合,

例1:一个类定义的对象作为另外一个类的成员变量 =》 成员对象 例2: 班级和建筑

class A
{
public:
    int a;
protected:
    int b;
private:
    int c;
};

// A称作基类(父类) B称作派生类(子类)
// B从A继承而来,A派生了B 
// 基类的成员继承过来后,不能大于继承方式
class B : private A  
{
public:
    //  “A::c”: 无法访问 private 成员
    void func() { cout << a << endl; }
    int d;
protected:
    int e;
private:
    int f;
};
int main()
{
    B bb;
    // 无法访问 protected 成员
    //cout << bb.a << endl;
}

基类在派生类中初始化问题

// 总结一下人的一些特征
class Base
{
public:
    Base(int data) :a_(data) { cout << "Base(int)" << endl; }
    ~Base() { cout << "~Base()" << endl; }
protected:
    int a_;
};

// 让老司机继承人的特征
class oldDriver : public Base
{
public:
    // 派生类只能初始化自己的成员,从基类继承来的成员只能靠调用基类的构造函数进行初始化
    oldDriver(int data) :b_(data), Base(data) { cout << "oldDriver(int)" << endl; }
    ~oldDriver() { cout << "~oldDriver()" << endl; }
private:
    int b_;
};

int main()
{
    oldDriver d(100);
}

继承的使用规则(下->上)

private和protected的区别吗? private和protected都可以保护成员不被外部访问,但是在继承结构有区别,

派生类继承基类private的成员,能继承但是无法访问; 继承基类protected成员,能继承,也能访问

// 总结一下人的一些特征
class Base
{
public:
    Base(int data) : a_(data) { cout << "Base(int)" << endl; }
    ~Base() { cout << "~Base()" << endl; }
protected:
    int a_;
};

// 让老司机继承人的特征
class  oldDriver : public Base
{
public:
    oldDriver(int data) : b_(data), Base(data) { cout << "oldDriver(int)" << endl; }
    ~oldDriver() { cout << "~Derive()" << endl; }
private:
    int b_;
};

int main()
{
    Base b(10);   // a_=10
    oldDriver old(20); // a_=20 b_=20
    // 总结:(后面的给前面的才可以)
    // 从上->下  不能转换
    // 从下->上  可以转换

    // 001
    // 不可以! 派生类对象 <= 基类对象   下 <= 上
    // old = b;

    // 002
    // 基类对象 <= 派生类对象     上 <= 下
    b = old;

    // 003
    // oldDriver*  <=  Base*  下 <= 上  不能转换
    // oldDriver* pd = &b;

    // 004
    // Base*  <=  oldDriver*  上 <= 下  可以转换
    Base* pb = &old;
}

静态绑定

1、基类指针可以指向派生类对象,但是只能访问派生类从基类继承来的成员 2、静态绑定和动态绑定

绑定: 函数的调用,编译阶段有明确的地址 静态绑定(编译阶段的绑定): 编译阶段call指令后面的函数调用是明确的, call 后是具体的函数 动态绑定(运行时的绑定): 运行的时候从虚函数表取出什么地址,这里就调用哪个函数 call eax

// 总结一下人的一些特征
class Base
{
public:
    Base(int data) : a_(data) {}
    ~Base() {}
     void Show() { cout << "Base::Show()" << endl; }
     void Show(int) { cout << "Base::Show(int)" << endl; }
protected:
    int a_;
};

// 让老司机继承人的特征
class  oldDriver : public Base
{
public:
    oldDriver(int data) : b_(data), Base(data) {};
    ~oldDriver() {};
    void Show() { cout << "oldDriver::Show()" << endl; }
private:
    int b_;
};

int main()
{
    oldDriver old(10);
    Base* p = &old;

    // Base::Show
    p->Show(); // call Base::Show 静态绑定

    cout << sizeof(Base) << endl;  // 4
    cout << sizeof(oldDriver) << endl;  // 8

    cout << typeid(p).name() << endl; // class Base*
    cout << typeid(*p).name() << endl;// class Base
}

动态绑定

// 总结一下人的一些特征
class Base
{
public:
    Base(int data) : a_(data) {}
    ~Base() {}
    virtual void Show() { cout << "Base::Show()" << endl; }
    virtual void Show(int) { cout << "Base::Show(int)" << endl; }
protected:
    int a_;
};

// 让老司机继承人的特征
class  oldDriver : public Base
{
public:
    oldDriver(int data) : b_(data), Base(data) {};
    ~oldDriver() {};
    void Show() { cout << "oldDriver::Show()" << endl; }
private:
    int b_;
};

int main()
{
    oldDriver old(10);
    Base* p = &old;

    /*
    Base::Show是虚函数,这里就要做动态绑定了
    p -> 对象的前四个字节vfptr
    vfptr -> 派生类对象的vftable
    再从vftable里面取出Show()函数的地址 => eax
    call eax   ====> 动态绑定,运行的时候从虚函数表取出什么地址,这里就调用哪个函数
    */
    p->Show();
    p->Show(10);

    cout << sizeof(Base) << endl; // 4  8   ?  这里面加上了vfptr
    cout << sizeof(oldDriver) << endl;// 8  12    继承了vfptr

    cout << typeid(p).name() << endl;
    // p是Base*  
    // *p是Base(解引用),但是一看Base里面有虚函数,就要识别RTTI类型
    cout << typeid(*p).name() << endl;
}

编译输出:
oldDriver::Show()
Base::Show(int)
8
12
class Base *
class oldDriver
评论区

索引目录