• (虚)函数 指针类型转换+指针和数组+各种默认值


     (虚)函数 指针类型转换

    1. 当父类里的不是虚函数时

    class A
    {
        public: void  f()
        {cout << "A" << " ";}
    };
    class B : public A
    {
        public: void  f()
        {cout << "B" << " ";}
    };
    int main(){
        A *pa = new A();
        pa->f();
        B *pb=(B *)pa;
        pb->f();
        delete pa, pb;
    
        pa=new B();
        pa->f();
        pb=(B *)pa;
        pb->f();
        return 0;
    }//输出A B A B
    View Code

    2. 当父类里的是虚函数时

    class A
    {
        public: void  virtual  f() //看清楚virtual的位置 在返回值oid的后面
        {cout << "A" << " ";}
    };
    class B : public A
    {
        public: void virtual  f()
        {cout << "B" << " ";}
    };
    int main(){
        A *pa = new A();
        pa->f();
        B *pb=(B *)pa;
        pb->f();
        delete pa, pb;
    
        pa=new B();
        pa->f();
        pb=(B *)pa;
        pb->f();
        return 0;
    }//输出A A B B
    View Code

    3. 举例

    using namespace std; 
    class A{ 
        public: 
            virtual void f() { cout << "A::f() "; } 
            void f() const { cout << "A::f() const "; } 
    }; 
    class B : public A { 
        public: 
            void f() { cout << "B::f() "; } 
            void f() const { cout << "B::f() const "; } 
    }; 
    void g(const A* a) { 
        a->f(); 
    } 
    int main(int argc, char *argv[]) { 
        A* p = new B(); 
        p->f(); 
        g(p); 
        delete(p); 
        return 0; 
    } // B::f() A::f() const
    /*g(p); 执行的是父类的f() const ,因为他不是虚函数
    由于f()在基类中声明为虚的,则p->f()根据对象类型(B)调用B::f(),此时编译器对虚方法使用动态联编,输出B::f()。
    由于f() const在基类中未声明为虚的,故p->f() const 根据指针类型(A)调用A::f() const,此时编译器对非虚方法使用静态联编,输出A::f() const。*/
    View Code

     规律如下:https://www.cnblogs.com/mu-tou-man/p/3925433.html

    当父类子类有同名非虚函数的时候,调用的是转换后的指针类型的函数;当父类子类有同名虚函数的时候呢,调用的是指针转换前指向的对象类型的函数。

    #include <iostream>
    using namespace std;
    class Base {
    public:
        virtual void f() { cout << "Base::f" << endl; }
        virtual void g() { cout << "Base::g" << endl; }
                void h() { cout << "Base::h" << endl; }
    
    };
    class Derived:public Base
    {
    public:
        virtual void f(){cout<<"Derived::f"<<endl;}
                void g(){cout<<"Derived::g"<<endl;}
                void h(){cout<<"Derived::h"<<endl;}
    };
    
    
    void main()
    {
        Base *pB=new Base();
        cout<<"当基类指针指向基类对象时:"<<endl;
        pB->f();
        pB->g();
        pB->h();
        cout<<endl;
    
        Derived *pD=(Derived*)pB;
        cout<<"当父类指针被强制转换成子类指针时:"<<endl;
        pD->f();
        pD->g();
        pD->h();
        cout<<endl;
    
        Derived *pd=new Derived();
        cout<<"当子类指针指向子类时候"<<endl;
        pd->f();
        pd->g();
        pd->h();
        cout<<endl;
    
        Base *pb=(Base *)pd;
        cout<<"当子类指针被强制转换成父类指针时:"<<endl;
        pb->f();
        pb->g();
        pb->h();
        cout<<endl;
    
        Base *pp=new Derived();
        cout<<"父类指针指向子类对象时候:"<<endl;
        pp->f();
        pp->g();
        pp->h();
        cout<<endl;
    }
    View Code

     https://blog.csdn.net/u011939264/article/details/52175504 

    https://blog.csdn.net/u014464706/article/details/22726659

    指针 二维指针

    1.  int * p[4]和int(*p)[4]  数组指针和指针数组

    int *p[4]; //定义一个指针数组,该数组中每个元素是一个指针,每个指针指向哪里就需要程序中后续再定义了。

    int (*p)[4]; //定义一个数组指针,该指针指向含4个元素的一维数组(数组中每个元素是int型)。

    区分int *p[n]; 和int (*p)[n]; 就要看运算符的优先级了。

    int *p[n]; 中,运算符[ ]优先级高,先与p结合成为一个数组,再由int*说明这是一个整型指针数组。

    int (*p)[n]; 中( )优先级高,首先说明p是一个指针,指向一个整型的一维数组。

     

    2. 

    main()
    {
    int a[5]={1,2,3,4,5};
    int *ptr=(int *)(&a+1);
    printf("%d,%d",*(a+1),*(ptr-1));
    }
    View Code

    输出为:2,5   https://blog.csdn.net/weixin_45905650/article/details/122121016

     &a :代指数组的整体的地址,这里的a是数组整体       a+1:代指数组的第一个成员,这里的a是数组首地址        

     

    &a和a做右值时的区别:

    如上图,&a是整个数组的首地址,而a是数组首元素的首地址。这两个在数字上是相等的,但是意义不相同。意义不相同会导致他们在参与运算的时候有不同的表现。

    &a是数组指针,其类型为int(* )[5]; 所以 &a+1就是int (* )[5]+1,如上图所示,&a+1就是相当于整个数组指针加1,执行&a+1后,ptr的偏移量相当于 a + sizeof(int) * 5 * 1。&a+2就是相当于整个数组指针加2,执行&a+2后,ptr的偏移量相当于 a + sizeof(int) * 5 * 2;这里之所以需要强制类型转换,因为类型不匹配:&a是int(* )[5];ptr是 int *类型; 要是输出*(ptr)====a[5]那就是个任意值了

    默认值

    struct xx{
       int a;
       int b;
    };
    void func1(void){
        int a;
        cout<<a<<endl;
    }
    void func2(void){
    
        static int a;
        cout<<a<<endl;
    
    }
    int b;
    int main()
    {
        //func1();//随机数
        //func2();//0
        //cout<<b;//0
        
        //xx t;  cout<<t.a<<" "<<t.b<<endl; //两个随机值
        //xx t={2};  cout<<t.a<<" "<<t.b<<endl;//2 0
        //xx t={1};  cout<<t.a/t.b<<endl; //不输出
    //全局变量和静态变量都是会自动初始化为0,堆和栈中的局部变量不会初始化而拥有不可预测的值。
    View Code

    sizeof计算

    struct str{
        char c;
        int a;
    };
    
    union uni{
        char c;
        int a;
    };
    
    void func(str arr[2]){
        char *str1="hello";
        char str2[]="hello";
        char str3[20]="hello";
        int p[5]={0,1,2,3,4};
    
         str st={0};
         uni un={0};
    
        cout<<sizeof(str1)<<endl;//4  表示的是指针的大小 占四个字节
        cout<<sizeof(str2)<<endl;//6  +'\0'
        cout<<sizeof(str3)<<endl;//20 :sizeof(指针和数组名的区别)
        cout<<sizeof(p)<<endl;//20 4x5!!
    
        cout<<sizeof(st)<<endl;//8    对齐
        cout<<sizeof(un)<<endl;//4 只按成员中最大的类型分配空间,所有成员共享这个内存空间
        //https://blog.csdn.net/weixin_44536482/article/details/89789278 还得是整数倍哦
    
        cout<<sizeof(arr)<<endl;//4  如果我们使用数组名作为函数参数,那么数组名会立刻转换为指向该数组第一个元素的指针。
    //C语言会自动的将作为参数的数组声明转换为相应的指针声明。
    //如果想得到数组的真实大小的话:将数组的引用作为参数int (&a)[]
    }
    
    int main()
    {
        str *arr1=new str[2];
        //cout<<sizeof(arr1)<<endl;//4 表示的是指针的大小 占四个字节
        //cout<<sizeof("hello")<<endl;//6  +'\0'
        func(arr1);
        return 0;
    }
    View Code

    关于union的sizeof

    new的初始化

    https://blog.csdn.net/u012494876/article/details/76222682      https://blog.csdn.net/aloneingchild/article/details/104600465

    int *p = new int[5];//都已经被初始化:错误
    int *p = new int[5]();//都已经被初始化:正确

    int* buffer = new int[512];
    //在默认情况下,new是不会对分配的int进行初始化的。要想使分配的int初始化为0,需要显式地调用其初始化函数:
    
    int* buffer = new int(); // 分配的一个int初始化为0
    int* buffer = new int(0); // 分配的一个int初始化为0
    int* buffer = new int[512](); // 分配的512个int都初始化为0
    
    //对于单个int,也可以初始化为非0值:
    int* buffer = new int(5); // 分配的一个int初始化为5
    //但是无法将分配的所有元素同时初始化为非0值,以下代码是不合法的:
    int* buffer = new int[512](0); // 语法错误!!!
    int* buffer = new int[512](5); // 语法错误!!!
    
    //C++11
    //C++11 中增加了初始化列表功能,所以也可以使用以下的方式进行初始化:
    int* buffer = new int{}; // 初始化为0
    int* buffer = new int{0}; // 初始化为0
    int* buffer = new int[512]{}; // 512个int都初始化为0
    int* buffer = new int{5}; // 初始化为5
    //与上面不同的是,如下写法是合法的:
    int* buffer = new int[512]{5}; // 第一个int初始化为5,其余初始化为0
    /*8仅仅是将第一个int初始化为5,其余的511个仍然初始化为0!
    而且正如初始化列表中“列表”两字所指出的,我们实际上可以用一个列表来初始化分配的内存:*/
    int* buffer = new int[512]{1, 2, 3, 4}; // 前4个int分别初始化为1、2、3、4,其余int初始化为0
    View Code

    C++在new时的初始化的规律可能为:对于有构造函数的类,不论有没有括号,都用构造函数进行初始化;如果没有构造函数,则不加括号的new只分配内存空间,不进行内存的初始化,而加了括号的new会在分配内存的同时初始化为0。()不等于(0)

    int *p = new int[10]; // 每个元素都没有初始化    有随机值不等于被初始化
    int *p = new int[10] (); // 每个元素初始化为0
    int *p = new int(7); // 元素初始化为7
    int *p = new int(); // 元素初始化为0
    int *p = new int; // 元素没有初始化
    string *p = new string[10]; // 每个元素调用默认构造函数初始化
    string *p = new string[10](); // 每个元素调用默认构造函数初始化
  • 相关阅读:
    有一群志同道合的程序员朋友是怎样的体验?
    hdu1387 模拟队列
    hau 1870 愚人节的礼物(栈)
    hdu1509 优先队列
    hdu1837 看病要排队(优先队列)
    hdu 1237 简单计算器(栈处理)
    hdu1022 模拟栈
    又一个错误的认知!
    jmeter+ant+jenkins 接口自动化测试持续集成(送源码)
    P1197 [JSOI2008]星球大战
  • 原文地址:https://www.cnblogs.com/yundong333/p/15983116.html
Copyright © 2020-2023  润新知