//virtual关键字--构造函数深刻理解 #include<iostream> using namespace std; /* C语言编译器,c++编译器全部是静态链编,就是一段一段代码的编译,不会考虑上下文 例如编译到void ProtectA(Point pin) 编译器就会认为pin就是Point类型, 而不会去联系上下文,去分析pin有没有可能是子类对象 virtual关键字会自动检测这个父类对象有没有是子类对象 */ /* virtual关键字的作用 假设父类中存在用virtual关键字修饰的函数A,在子类中重写了该函数 当变量是父类时,c++编译器会检测传递过来的变量是不是子类对象, 如果传过来的是子类对象,那么c++编译器会自动调用子类的同名函数A, 如果传过来的是父类对象,那么c++编译就无法访问子类的同名函数A,只能调用父类的函数A */ class Point{ public: Point(Point &p){ cout << "我是父类,拷贝构造函数被执行了1" << endl; //this= 报错 这里发现 this的类型是 Point *const this 说明在执行构造函数之前就已经被分配内存空间了 //进一步说明,构造函数知识单纯的给成员属性赋值,并不会分配内存空间 //分配内存空间肯定是在定义的时候分配 //PointA pa; 这么定义的时候 直接已经在栈中分配内存 调用无参构造函数初始化 //Point *pa=new Point() 这么定义 已经在堆里分配内存 调用无参构造函数初始化 //总结;构造函数只是初始化成员属性,并不分配内存 this->x = p.x; this->y = p.y; } Point(int a = 1, int b = 1){ this->x = a; this->y = b; } virtual void Print(){ cout << "x=" << x << endl; } private: int x; int y; }; class PointA :public Point{ public: void Print(){ cout << "我是子类,我重写的父类的成员函数" << endl; } }; //赋值兼容原则 void ProtectA(Point pin){ pin.Print(); } void ProtectC(Point &pin){ pin.Print(); } void ProtectD(Point *pin){ pin->Print(); } void ProtectB(){ PointA pa; ProtectA(pa); //这里发现 打印的是 x=乱码 ------ 没有调用子类的Print()函数? //这个错误是因为ProtectA(Point pin), //调用ProtectA()函数, //①执行父类拷贝构造函数 //②产生新的父类临时对象pin(此时pin已经是父类对象,他执行的是拷贝构造函数) //③父类对象调用virtual关键字修饰的函数, //c++编译会在父类内存区域向后搜索子类属性,发现没有子类属性 //c++编译器判断这个对象时父类对象,直接调用父类的Print() ProtectC(pa); ProtectD(&pa); } void main(){ ProtectB(); system("pause"); }
时间: 2024-10-18 21:20:51