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

 

 (虚)函数 指针类型转换

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](); // 每个元素调用默认构造函数初始化

 

posted @ 2022-03-08 23:31  像走了一光年  阅读(94)  评论(0编辑  收藏  举报