//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->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; /* PointA pa;详解: 这句话执行了Point类的Point(int a = 1, int b = 1)构造函数, 此时子类对象pa中的父类成员x=1,y=1,虽然x,y无法在子类pa中访问 */ ProtectA(pa); //调用void ProtectA(Point pin)函数, //①执行父类拷贝构造函数 注意此时pa中的父类成员x,y都是有值的,也因此x=1,而不是乱码 //②产生新的父类临时对象pin(此时pin已经是父类对象,他执行的是拷贝构造函数) //③父类对象调用virtual关键字修饰的函数, //c++编译会在父类内存区域向后搜索子类属性,发现没有子类属性 //c++编译器判断这个对象时父类对象,直接调用父类的Print() ProtectC(pa); ProtectD(&pa); } void main(){ ProtectB(); system("pause"); }