IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> C++知识库 -> C++之派生类向上转型赋值基类 -> 正文阅读

[C++知识库]C++之派生类向上转型赋值基类

派生类对象赋值给基类对象

#include <iostream>

using namespace std;

class A {
public:
    A(int a_parameters);

    void display();

    int get_a();

private:
    int a;
};

A::A(int a_parameters) : a(a_parameters) {}

void A::display() { cout << "a:" << a << endl; }

int A::get_a() { return this->a; }

class B : public A {
public:
    B(int a_parameters, int b_parameters);

    void display();

private:
    int b;
};

B::B(int a_parameters, int b_parameters) : A(a_parameters), b(b_parameters) {}

void B::display() { cout << "a:" << get_a() << ":b:" << b << endl; }

int main() {
    system("chcp 65001");
    cout << "基类和派生类初始化" << endl;
    A a(3);
    B b(5, 6);
    a.display();
    b.display();
    cout << "--------------------" << endl;
    cout << "B向上转型将对象的值赋给A" << endl;
    a = b;
    a.display();
    b.display();
    return 0;
}
输出:
Active code page: 65001
基类和派生类初始化
a:3
a:5:b:6
--------------------
B向上转型将对象的值赋给A
a:5
a:5:b:6

赋值是将已有的数据写入分配好的内存中,对象的内存只包含了成员变量,所以对象之间的赋值是成员变量的赋值。成员函数不存在赋值。对象之间的赋值不会影响成员函数,也不会影响this指针。上述程序中,虽然将b对象赋值给了a,实际上是将b中覆盖a成员变量的值重新赋值给了a中的成员变量,对于a.display()还是调用的a中定义的成员函数,并且this指针指向的还是对象a。
只能通过派生类赋值给基类,而不能够使用基类赋值派生类,因为派生类继承自基类,基类中非私有属性的成员变量在派生类中也存在,但是派生类会新增成员变量,在基类中并不存在,就无法将基类对象赋值给派生类对象。同理,同一基类的不同派生类中的对象之间也无法相互赋值。

派生类指针赋值给基类指针

#include <iostream>

using namespace std;

class A {
public:
    A(int a_parameters);

    void display();

    int get_a();

private:
    int a;
};

A::A(int a_parameters) : a(a_parameters) { cout << "A constructed is created" << endl; }

void A::display() { cout << "a:" << a << endl; }

int A::get_a() { return this->a; }

class B : public A {
public:
    B(int a_parameters, int b_parameters);

    void display();

    int get_b();

private:
    int b;
};

B::B(int a_parameters, int b_parameters) : A(a_parameters), b(b_parameters) {
    cout << "B constructed is created" << endl;
}

void B::display() { cout << "b_a:" << get_a() << "b_b:" << get_b() << endl; }

int B::get_b() { return this->b; }

class C {
public:
    C(int c_parameters);

    void display();

    int get_c();

private:
    int c;
};

C::C(int c_parameters) : c(c_parameters) { cout << "C constructed is created" << endl; }

void C::display() { cout << "c:" << c << endl; }

int C::get_c() { return this->c; }

class D : public B, public C {
public:
    D(int a_parameters, int b_parameters, int c_parameters, int d_parameters);

    void display();

    int get_d();

private:
    int d;
};

D::D(int a_parameters, int b_parameters, int c_parameters, int d_parameters) : B(a_parameters, b_parameters),
                                                                               C(c_parameters) {
    cout << "D constructed is created" << endl;
}

void D::display() { cout << "a:" << get_a() << ":b:" << get_b() << ":c" << get_c() << ":d:" << get_d() << endl; }

int D::get_d() { return this->d; }

int main() {
    A *pa = new A(1);
    B *pb = new B(2, 3);
    C *pc = new C(5);
    D *pd = new D(6, 7, 8, 9);
    pa = pd;
    pa->display();
    pb = pd;
    pb->display();
    pc = pd;
    pc->display();
    cout << "pa=" << pa << endl;
    cout << "pb=" << pb << endl;
    cout << "pc=" << pc << endl;
    cout << "pd=" << pd << endl;
    return 0;
}
输出:
A constructed is created
A constructed is created
B constructed is created
C constructed is created
A constructed is created
B constructed is created
C constructed is created
D constructed is created
a:6
b_a:6b_b:7
c:8
pa=0x6d1ae0
pb=0x6d1ae0
pc=0x6d1ae8
pd=0x6d1ae0

通过上述程序发现,尽管将最终派生类D的对象指针pd指向了间接基类A,基类B和基类C,但是pa,pb,pc指向了pd后,却不能调用派生类D的成员函数,只能调用D的成员变量,因此就出现了基类A的指针pa指向pd后,仍然调用的是A的display(),pb,pc同理。一句话总结就是C++通过指针来访问成员变量,通过指针的类型来访问成员函数。

从上述结果中发现,pa,pb,pd指向的地址一致,但是pc指向的地址却比三个指针指向的地址都大,这是因为虽然赋值是将一个变量的值给另一个变量,但是赋值前编辑器可能会对现有的值进行处理,比如float变量赋值给int变量,就会舍弃小数部分,这样等式左右两边的值就不相等。将基类指针指向派生类指针的时候,编译器可能会在赋值前进行处理。我们知道,对象的指针必须要指向对象的起始位置。例如上述程序,基类A和B,他们对象的起始地址和D对象的起始地址是一样的,所以他们指向的内存都是一块内存。而C类对象和D类对象的起始位置有一定的偏移,当pc指向pd时,要算上这个偏移,这样pc才能指向C类对象的起始位置,这样就存在了上述中赋值前编译器对值进行了处理,这样就导致了pc指向的地址和其他三个指针指向的地址不一样的情况。

基类引用指向派生类引用

和基类指针指向派生类指针一样,只引用了派生类的成员变量,而不能引用派生类的成员函数。修改上述main()代码

int main() {
    D d(1, 2, 3, 5);
    A &a = d;
    B &b = d;
    C &c = d;
    a.display();
    b.display();
    c.display();
    cout << "a_address:" << &a << endl;
    cout << "b_address:" << &b << endl;
    cout << "c_address:" << &c << endl;
    cout << "d_address:" << &d << endl;
    return 0;
}
输出:
A constructed is created
B constructed is created
C constructed is created
D constructed is created
a:1
b_a:1b_b:2
c:3
a_address:0x63fdf0
b_address:0x63fdf0
c_address:0x63fdf8
d_address:0x63fdf0

引用和指针的表现之所以如此类似,是因为引用和指针并没有本质上的区别,引用仅仅是对指针进行了简单封装。

  C++知识库 最新文章
【C++】友元、嵌套类、异常、RTTI、类型转换
通讯录的思路与实现(C语言)
C++PrimerPlus 第七章 函数-C++的编程模块(
Problem C: 算法9-9~9-12:平衡二叉树的基本
MSVC C++ UTF-8编程
C++进阶 多态原理
简单string类c++实现
我的年度总结
【C语言】以深厚地基筑伟岸高楼-基础篇(六
c语言常见错误合集
上一篇文章      下一篇文章      查看所有文章
加:2021-07-24 23:54:43  更:2021-07-24 23:54:55 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年5日历 -2024/5/3 8:09:14-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码