作者:良知犹存
转载授权以及围观->欢迎添加Wx:Allen-Iverson-me-LYN
前言:本文为C++使用过程中的一些细节知识补充,碎片化的知识.其中有韦东山老师和其他博主一些知识笔记,在此谢谢韦老师以及各博主的文章博客,受益良多.
一、多重定义会使程序进行基类调用,用virtual定义基类的程序函数,然后派生类(子类)进行虚拟函数继承调用,调用的时候内存占用以及编译执行情况是如何呢?
联编机制:联编是指一个程序自身彼此关联的一个过程,按照联编所进行的阶段不同分为静态联编和动态联编.
1.静态联编,对于一般类的成员函数(非虚函数),在编译的时候就确定好了调用哪一个。而编译时所进行的联编又称为静态束定(束定是指确定所调用的函数与执行该函数代码之间的关系).
2.动态联编,在运行过程中解决选择调用函数与执行该函数代码之间的关系,又被成为动态束定。具体为:有一个指针,指向一个虚函数表;在调用的时候通过指针找到表,调用虚函数,进而将虚函数连接到当前类下。所以试下动态联编首先要有继承性,并且要求建立子类型关系,其次,一个重要条件是虚函数,继承是动态联编的基础,虚函数是动态联编的关键.
普通继承:静态联编
虚拟继承:动态联编
一般函数名字相同返回值不同的时候只能做重载不能进行虚拟函数,但是如果返回值是本次定义的类的指针或者引用时,虚拟函数才成立。
二、虚拟析构函数,将析构函数定义为虚函数,但是需要注意,如果我们派生类分配了内存空间.但是基类的析构函数不是虚析构函数的情况下,类执行析构函数的时候只执行基类析构函数,派生类则没有,造成内存泄漏.
class D{......}; class B: public D{......}; int main(int argc, char **argv) { D* d = new b; return 0; }
using namespace std; class Human { private: int a; public: virtual void eating(void) { cout<<"use hand to eat"<<endl; } virtual ~Human() { cout<<"~Human()"<<endl; } virtual Human* test(void) { cout<<"Englishman test()"<<endl; return this; } }; class Englishman : public Human { public: void eating(void) { cout<<"use knife to eat"<<endl; } virtual ~Englishman() { cout<<"~Englishman()"<<endl; } virtual Englishman* test(void) { cout<<"Englishman test()"<<endl; return this; } }; class Chinese : public Human { public: void eating(void) { cout<<"use chopsticks to eat"<<endl; } virtual ~Chinese() { cout<<"~Chinese()"<<endl; }/*析构函数也应该为虚拟函数*/ virtual Chinese* test(void) { cout<<"Chinese test()"<<endl; return this; } }; void test_eating(Human h){ h.eating(); } void test_return(Human h){ h.test(); } int main(int argc, char **argv) { Human h; Englishman e; Chinese c; test_return(h); test_return(e); test_return(c); return 0; }
三、动态类型转化中经常使用指针,一般不适用引用,因为引用在被转换判断的时候,实体可能不存在,引用指向也就没有意义,程序就会执行失败。
/*类的定义和上面范例定义相同,此处就不多做赘述*/ void test_eating(Human &h) { #if 0/*有隐患*/ Englishman &pe = reinterpret_cast<Englishman&>(h);/*静态显性强制转化*/ Chinese &pc = reinterpret_cast<Chinese&>(h); Guangximan &pg = reinterpret_cast<Guangximan&>(h); #else // Englishman &pe = dynamic_cast<Englishman&>(h);/*error*/ Chinese &pc = dynamic_cast<Chinese&>(h); /*动态转换*/ Guangximan &pg = dynamic_cast<Guangximan&>(h); #endif h.eating(); /*想分辨哪个国家的人*/ } void test_return(Human h) { h.test(); } int main(int argc, char **argv) { Human h; Guangximan g; Englishman *pe; pe = static_cast<Englishman*>(&h); // Englishman *pe2 = static_cast<Englishman*>(&g); Chinese *pc = static_cast<Chinese*>(&g); test_eating(g); return 0; }
四、类与派生类之间:函数名相同,参数与返回值也同样相同的函数叫做覆写函数,函数名相同参数不同叫做重载函数。
覆写函数通常应用于子类继承父类时,重写父类中的函数,覆写的函数不能在父类中为private,否则只是相当于在子类中新写了一个函数.
C++允许在同一作用域中的某个函数和运算符指定多个定义,分别成为重载函数和重载运算符.
namespace C { using namespace std; class Point { private: int x; int y; public: Point() { std::cout << "/* Point() */" << std::endl; } Point(int x,int y) : x(x),y(y) { std::cout << "/* Point(int x,int y) */" << std::endl; } Point(const Point& p) { std::cout << "Point(const Point& p)" << std::endl; x = p.x; y = p.y; } ~Point() { std::cout << "/* ~Point() */" << std::endl; } int getX(){return x;} int getY(){return y;} int setX(int x){this->x = x;} int setY(int y){this->y = y;} void printInfo() { cout<<"("<<x<<","<<y<<")"<<endl; } friend Point add(Point &p1,Point &p2); friend Point operator+(Point &p1,Point &p2); friend Point operator++(Point &p,int a); friend Point operator++(Point &p); }; Point add(Point &p1,Point &p2) { Point n ; n.x=(p1.x+p2.x); n.y=(p1.y+p2.y); return n ; } Point operator+(Point &p1,Point &p2) { cout<<"Point operator+(Point &p1,Point &p2)"<<endl; Point n ; n.x=(p1.x+p2.x); n.y=(p1.y+p2.y); return n ; } /*Point p(1,2); ++p 函数重载 通过参数的不一致进行区分*/ Point operator++(Point &p) { std::cout << "++p" << std::endl; p.x += 1; p.y += 1; return p; } /*Point p(1,2); p++ */ Point operator++(Point &p,int a) { std::cout << "p++" << std::endl; Point n; n = p; p.x += 1; p.y += 1; return n; } } #include "point.h" using namespace C; int Person::cnt = 0; /*定义和初始化 此处并不是全局变量*/ int main(int argc,char** argv) { Point p1(1,2); Point p2(2,3); std::cout << "begin" << std::endl; ++p1; p1.printInfo(); std::cout << "***********" << std::endl; p2++; p2.printInfo(); std::cout << "end" << std::endl; return 0; }