析构函数

C++------虚析构函数与纯虚析构函数

元气小坏坏 提交于 2019-12-07 06:57:04
#include <iostream> #include <string.h> using namespace std; //虚析构与纯虚析构 class Animal { public: virtual void speak() { cout << "动物在说话" << endl; } ~Animal() { cout << "Animal的析构调用" << endl; } }; class Cat :public Animal { public: Cat(const char* name) { this->m_Name = new char[strlen(name) + 1]; strcpy_s(this->m_Name, strlen(name) + 1, name); } void speak() { cout << "小猫也在说话" << endl; } ~Cat() { if (this->m_Name != NULL) { delete[] this->m_Name; this->m_Name = NULL; } cout << "小猫的析构函数" << endl; } char * m_Name; }; void test01() { Animal *cat1 = new Cat("Tom"); cat1->speak(); delete cat1; /

C++中虚析构函数和纯虚函数的作用

别来无恙 提交于 2019-12-07 06:56:53
一. 虚析构函数 为了能够正确的调用对象的析构函数,一般要求具有层次结构的顶级类定义其析构函数为虚函数。因为在delete一个抽象类指针时候,必须要通过虚函数找到真正的析构函数。 class Base { public : Base (){} virtual ~Base(){} }; class Derived: public Base { public : Derived (){}; ~Derived(){}; } void foo() { Base *pb; pb = new Derived; delete pb; } 这是正确的用法,会发生动态绑定,它会先调用Derived的析构函数,然后是Base的析构函数。 如果析构函数不加virtual,delete pb只会执行Base的析构函数,而不是真正的Derived析构函数。 因为不是virtual函数,所以调用的函数依赖于指向静态类型,即Base。 二. 纯虚析构函数 现在的问题是,我们想把Base做出抽象类,不能直接构造对象,需要在其中定义一个纯虚函数。如果其中没有其他合适的函数,可以把析构函数定义为纯虚的,即将前面的CObject定义改成: class Base { public : Base (){} virtual ~Base()= 0 }; 可是,这段代码不能通过编译,通常是link错误,不能找到~Base(

C++中的虚函数(virtual function)

╄→гoц情女王★ 提交于 2019-12-07 06:56:26
1.简介 虚函数是C++中用于实现多态(polymorphism)的机制。核心理念就是通过基类访问派生类定义的函数。假设我们有下面的类层次: class A { public: virtual void foo() { cout << "A::foo() is called" << endl;} }; class B: public A { public: virtual void foo() { cout << "B::foo() is called" << endl;} }; 那么,在使用的时候,我们可以: A * a = new B(); a->foo(); // 在这里,a虽然是指向A的指针,但是被调用的函数(foo)却是B的! 这个例子是虚函数的一个典型应用,通过这个例子,也许你就对虚函数有了一些概念。它虚就虚在所谓“推迟联编”或者“动态联编”上,一个类函数的调用并不是在编译时刻被确定的,而是在运行时刻被确定的。由于编写代码的时候并不能确定被调用的是基类的函数还是哪个派生类的函数,所以被成为“虚”函数。 虚函数只能借助于指针或者引用来达到多态的效果,如果是下面这样的代码,则虽然是虚函数,但它不是多态的: class A { public: virtual void foo(); }; class B: public A { virtual void foo(); };

c++的虚析构函数和纯虚析构函数

泄露秘密 提交于 2019-12-07 06:56:12
虚函数是用作实现子类的多态性的,它可以在运行的过程中选择子类或者父类的同名函数,意思就是说,每次只有一个函数运行。 但是对于析构函数来说,子类 与父类在销毁对象时,都应该要调用 ,所以把父类的析构函数定义为虚函数,会发生什么事情呢。 class { public: A(){cout<<"A constructor"<<endl;} virtual ~A(){count<<"A delete"<<endl;} }; class B:public A { public B(){cout<<"B constructor"<<endl;} public ~B(){cout<<"B delete"<<endl;} }; int main() { A *p = new B(); return 0; } 可以发现,A 和 B都调用了析构函数,这时如果把A类的virtual 去掉,那么就不会调用B的析构函数了。 为什么呢?因为父类只能调用子类中继承父类的方法,而如果需要父类调用以属于子类实现的方法,那么只有把父类中同名的方法设置成虚函数,所以把父类的析构函数设置为虚函数,父类才能调用子类的析构函数。 所以把基类的析构函数写为虚函数与其它成员函数写作虚函数是不一样的。 还有一个问题就是为什么不能把构造函数设置成虚函数? 1.因为虚函数是用来实现多态,如果把基类的构造函数设置成虚函数后

C++中虚析构函数的作用

断了今生、忘了曾经 提交于 2019-12-07 06:54:24
我们知道,用C++开发的时候,用来做基类的类的析构函数一般都是虚函数。可是,为什么要这样做呢?下面用一个小例子来说明: 有下面的两个类: class ClxBase { public : ClxBase() {}; virtual ~ ClxBase() {}; virtual void DoSomething() { cout << " Do something in class ClxBase! " << endl; }; }; class ClxDerived : public ClxBase { public : ClxDerived() {}; ~ ClxDerived() { cout << " Output from the destructor of class ClxDerived! " << endl; }; void DoSomething() { cout << " Do something in class ClxDerived! " << endl; }; }; 代码 ClxBase * pTest = new ClxDerived; pTest -> DoSomething(); delete pTest; 的输出结果是: Do something in class ClxDerived! Output from the destructor of

c++纯虚析构函数

拥有回忆 提交于 2019-12-07 06:51:59
纯虚析构函数和虚析构函数的区别在于 纯虚析构函数一般用于将类定义为抽象类,这时候有同学会问啦?抽象类不是定义一般成员方法的吗?原因是这样的,当我们在类里面实在找不到可以定义为纯虚函数的成员方法的时候,这时候可以将析构函数定义为纯析构函数; 纯虚构函数的实现需要注意以下几个地方: 通常的纯虚函数不需要函数体,是因为我们一般不会调用抽象类的这个函数,只会调用派生类的对应函数,但是父类纯虚构函数需要要函数体,因为我们知道,当子类继承父类的时候,假如父类存在纯虚函数,子类需要实现该函数,否则就会报错。 纯虚析构函数也一样,也需要实现,可是呢?能不能像通常的纯虚函数一样,在子类重写即可,可是,有见过析构函数重写的吗,这时候的做法是给 纯虚析构函数指定函数体 #include <iostream> using namespace std ; class Father { public : virtual ~ Father () = 0 ; }; class Son : public Father { public : ~ Son (){} }; int main( int argc, char *argv[]) { cout << "Hello World!" << endl; Father *father = new Son ; delete father; return 0 ; }

C++纯虚析构函数

不问归期 提交于 2019-12-07 06:51:47
图说C++对象模型:对象内存布局详解:https://blog.csdn.net/suchto/article/details/54947869?fps=1&locationNum=9 原文:https://blog.csdn.net/yby4769250/article/details/7294733 纯虚析构函数和普通纯虚函数的区别在于,纯虚析构函数需要提供函数的实现,而一般纯虚函数不能有实现,这样的原因在于,纯虚析构函数最终需要被调用,以析构基类对象,虽然是抽象类没有实体。而如果不提供该析构函数的实现,将使得在析构过程中,析构无法完成而导致析构异常的问题 Calss A { public: A(){} virtual ~A()=0; } A::~A(){} ClassB:public A { } A *p =new B(); Delete p;// 通过父类指针去析构子类对象,分三种情况: 1 、父类如 A 的析构函数不是虚函数,这种情况下,将只会调用 A 的析构函数而不会调用子类的析构函数,前面的文章中有提到过,非虚函数是通过类型来寻址的,这样的析构将会导致析构畸形 2 、父类如 A 的析构函数是普通的虚函数,这种情况下,会很正常,从子类一直析构到基类,最后完成析构 3 、父类如 A 的析构函数是纯析构函数,如本文所提,正是重点,在这种情况之下,由于析构函数首先是虚函数

为什么必须提供纯虚析构函数的定义

最后都变了- 提交于 2019-12-07 06:51:36
转载:http://blog.chinaunix.net/uid-25544300-id-3236826.html 部分修改,感谢博主! 在 某些类里声明纯虚析构函数很方便。纯虚函数将产生抽象类——不能实例化的类(即不能创建此类型的对象)。有些时候,你想使一个类成为抽象类,但刚好又没有 任何纯虚函数。怎么办?因为抽象类是准备被用做基类的,基类必须要有一个虚析构函数,纯虚函数会产生抽象类,所以方法很简单:在想要成为抽象类的类里声明 一个纯虚析构函数。 class awov { public:   virtual ~awov() = 0; // 声明一个纯虚析构函数 }; 这个类有一个纯虚函数,所以它是抽象的,而且它有一个虚析构函数,所以不会产生析构函数问题。但这里还有一件事:必须提供纯虚析构函数的定义: awov::~awov() {} // 纯虚析构函数的定义 这个定义是必需的,因为虚析构函数工作的方式是:最底层的派生类的析构函数最先被调用,然后各个基类的析构函数被调用。这就是说,即使是抽象类,编译器也要产生对~awov()的调用,所以要保证为它提供函数体。如果不这么做,链接器就会检测出来,最后还是得回去把它添上。 虽然抽象类的析构函数可以是纯虚函数,但要实例化其派生类对象,仍必须提供抽象基类中析构函数的函数体。 转载于:https://www.cnblogs.com

基类的纯虚析构函数一定要予以实现

穿精又带淫゛_ 提交于 2019-12-07 06:51:19
Effective C++ 条歀07:为多态基类声明virtual析构函数(Declare destructors virtual in polymorphic base classes) 纯虚函数 纯虚函数是一种特殊的虚函数,在许多情况下,在基类中不能对虚函数给出有意义的实现,而把它声明为纯虚函数,它的实现留给该基类的派生类去做。这就是纯虚函数的作用。 虚函数是C++语言的精髓。含有纯虚函数的类被称为抽象类,不能被实例化生成对象,只能派生。由它派生的类的纯虚函数如果没有被实现,那么,该派生类还是个抽象类。 只有全部实现了纯虚函数的派生类才可以被实例化。 纯虚函数的可定义性 定义一个函数为纯虚函数,一般表示该函数没有被实现。但是,这不代表纯虚函数不能被实现。 纯虚函数也是可以定义的 。 纯虚析构函数 虚析构函数是为了让通过基类指针或引用可以正确释放派生类对象。有时候如果想让基类成为一个抽象类,也就是不能被实例化,可以为类引入一个纯虚函数。但如果手上没有任何pure virtual函数时,该怎么办?由于抽象类总是会被作为基类用于派生的,而基类就该有一个虚的析构函数,并且由纯虚函数可以导致抽象类。所以常常把基类的析构函数声明为纯虚析构函数。又由于所有对象析构时,最后都会调用其基类的析构函数,所以 基类的析构函数必须有定义 。纯虚析构函数也不例外。 所以,

究竟是什么毁了我的impl实现

我的梦境 提交于 2019-12-06 16:37:16
Impl模式早就有过接触(本文特指通过指针完成impl),我晓得它具有以下优点: 减少头文件暴露出来的非必要内部类(提供静态库,动态库时尤其重要); 减小文件间的编译依存关系,大型代码库的编译时间就不会那么折磨人了。 Impl会带来性能的损耗,每次访问都因为指针增加了间接性,还有一个微小的指针内存消耗。但是基于以上优点,除非你十分确定它造成了性能损耗,否则就让它存在吧。 Qt中大量使用Impl,具体可见https://wiki.qt.io/D-Pointer中关于Q_D和Q_Q宏的解释。 然而,如何使用智能指针,我是说基于std::unique_ptr实现正确的impl模式,就有点意思了。 错误做法 #include <boost/noncopyable.hpp> #include <memory> class Trace1 : public boost::noncopyable { public: Trace1(); ~Trace1() = default; void test(); private: class TraceImpl; std::unique_ptr<TraceImpl> _impl; }; 这是我初版代码,关于_impl的实现细节,存放于cpp中,如下所示: class Trace1::TraceImpl { public: TraceImpl() =