zoukankan      html  css  js  c++  java
  • C++的同名属性(没有虚拟属性)、同名普通函数、同名静态函数(没有虚拟静态函数),是否被覆盖

    例子1:属性的覆盖
    #include "stdafx.h"

    class A {
    public:
    int i;
    A() { i=1; }
    };

    class B: public A {
    public:
    int i;
    B() { i=2; }
    };

    class C: public B {
    public:
    int i;
    C() { i=3; }
    };


    int main(int argc, char* argv[])
    {
    A* a1 = new A(); printf(" %d ", a1->i);
    A* a2 = new B(); printf(" %d ", a2->i);
    A* a3 = new C(); printf(" %d ", a3->i);

    printf(" %d ", ((B*)a2)->i);
    printf(" %d ", ((B*)a3)->i);
    printf(" %d ", ((C*)a3)->i);

    return 0;
    }

    输出:
    1
    1
    1
    2
    2
    3
    结论:按照指针的定义类型来读取相关类的属性。大概三个属性在内存里都存在。有虚函数,但是没有虚数据成员!指针是什么类型(不管它指向什么对象),数据成员就是什么。

    printf(" %d ", sizeof(*a1)); // 这里,也是严格按照指针类型走。
    printf(" %d ", sizeof(*a2));
    printf(" %d ", sizeof(*a3));


    同理:
    int main(int argc, char* argv[])
    {
    A a1; printf(" %d ", a1.i);
    B a2; printf(" %d ", a2.i);
    C a3; printf(" %d ", a3.i);

    printf(" %d ", ((A)a2).i); // 向上强制转换,变成A类型对象,则读取A的i
    printf(" %d ", ((B)a3).i); // 向上强制转换,变成B类型对象,则读取B的i

    return 0;
    }
    输出:
    1
    2
    3
    1
    2
    结论:按照对象类型来读取相关类的数据成员。完全与Java一致。
    (与Java比较,Java只有指针类型,而没有对象类型,即只要研究前一种情况即可)


    例子2.1:误入函数参数的强制转换
    #include "stdafx.h"

    class A {
    public:
    virtual void get(int i) { printf("int in A: %d ", i); }
    virtual void get(double d) { printf("double in A: %f ", d); }
    };

    class B: public A {
    public:
    virtual void get(int i) { printf("int in B: %d ", i); }
    };

    int main(int argc, char* argv[])
    {
    A* pA = new A(); pA->get(1); pA->get(2.2);
    A* pAB = new B(); pAB->get(1); pAB->get(2.2);
    B* pB = new B(); pB->get(1); pB->get(2.2); // warning

    return 0;
    }
    编译:
    warning C4244: 'argument' : conversion from 'const double' to 'int', possible loss of data
    输出:
    int in A: 1
    double in A: 2.200000
    int in A: 1
    double in A: 2.200000
    int in B: 1
    int in B: 2 // 注意,C++更倾向于做参数的强制转换,好继续调用int,而不是调用父类函数的get(double d)。但这不是覆盖父类同名函数覆盖


    int main(int argc, char* argv[])
    {
    A a; a.get(1); a.get(2.2);
    A ab; ab.get(1); ab.get(2.2);
    B b; b.get(1); b.get(2.2); // warning

    return 0;
    }
    编译:
    warning C4244: 'argument' : conversion from 'const double' to 'int', possible loss of data
    输出:
    int in A: 1
    double in A: 2.200000
    int in A: 1
    double in A: 2.200000
    int in B: 1
    int in B: 2 // 注意,C++更倾向于做参数的强制转换,好继续调用int,而不是调用父类函数的get(double d)。但这不是覆盖父类同名函数覆盖


    结论:函数参数强制转换后的调用优先级比父类虚拟函数更高

    注意:
    1. C++函数不是默认virtual的。所以把上面的virtual都去掉的话,也会掉入那个参数强制转换的陷阱。
    2. C++默认属性是private(如果不写明的话)


    例子2.2:似乎存在子类一个函数覆盖父类全部同名函数的问题(还是有点怀疑),这点与Java不一样。
    #include "stdafx.h"

    class A {
    private:
    int i;
    public:
    A() { i=3; }
    virtual void get(int i) { printf("int in A: %d ", i); }
    virtual void get(A a) { printf("double in A: %d ", i); } // 注意,如果这里写%f编译没错,运行出错。可能double占的字节更多吧。
    };

    class B: public A {
    private:
    int i;
    public:
    B() { i=4; }
    virtual void get(int i) { printf("int in B: %d ", i); }
    };

    int main(int argc, char* argv[])
    {
    A a; a.get(1); a.get(a);
    A ab; ab.get(1); ab.get(a);
    B b; b.get(1);
    b.get(a); // 编译不过,说不能把A转成int

    return 0;
    }

    注意,这个例子还深挖一下,因为有一个private i,如果同名函数调用的话,到底调用谁呢?试了,数据成员跟着对象类型走。


    例子3:测试静态函数覆盖问题
    #include "stdafx.h"

    class A {
    private:
    int i;
    public:
    A() { i=3; }
    static void get(int i) { printf("int in A: %d ", i); }
    };

    class B: public A {
    private:
    int i;
    public:
    B() { i=4; }
    static void get(int i) { printf("int in B: %d ", i); }
    };

    int main(int argc, char* argv[])
    {
    A::get(1);
    B::get(2);
    A a; a.get(1);
    B b; b.get(2);
    ((A)b).get(3); // 里,按转换后的A类型调用静态函数
    A* pa = new A(); pa->get(1);
    A* pab = new B(); pab->get(1); // 这里,按指针类型A调用静态函数(静态函数是死脑筋,死跟着最简单的指针类型走,不像虚函数那样脑筋灵活)
    B* pb = new B(); pb->get(2);
    ((A*)pb)->get(2); // 这里,按转换后的指针类型调用静态函数

    return 0;
    }
    输出:
    int in A: 1
    int in B: 2
    int in A: 1
    int in B: 2
    int in A: 3
    int in A: 1
    int in A: 1
    int in B: 2
    int in A: 2

    结论:静态函数跟着指针类型走(毕竟静态函数不是虚拟函数),而不是指针指向的对象类型走。这一点,跟数据成员一致。

    注意:静态函数不能调用对象的属性,以下是无法编译通过的:

    class A {
    private:
    int i;
    public:
    A() { i=3; }
    static void get() { printf("int in A: %d ", i); }
    };

  • 相关阅读:
    早该知道的7个JavaScript技巧
    ASP.NET 实现伪静态网页方法
    Nginx http大文件断点续传分块上传
    java http大文件断点续传分块上传
    B/S http大文件断点续传上传
    前端 http大文件断点续传上传
    百度WebUploader http大文件断点续传上传
    webuploader http大文件断点续传上传
    ceph 之recovery machhine
    docker private registry使用
  • 原文地址:https://www.cnblogs.com/findumars/p/3297960.html
Copyright © 2011-2022 走看看