析构函数

【总结】虚函数小结

自作多情 提交于 2019-12-12 01:42:50
虚函数小结 1) 虚函数是动态绑定的,也就是说,使用虚函数的指针和引用能够正确找到实际类的对应函数,而不是执行定义类的函数。这是虚函数的基本功能,就不再解释了。 2) 构造函数不能是虚函数。而且,在构造函数中调用虚函数,实际执行的是父类的对应函数,因为自己还没有构造好, 多态是被disable的。 3) 析构函数可以是虚函数,而且,在一个复杂类结构中,这往往是必须的(delete 指向子类的父类指针时,不会析构子类)。 4) 将一个函数定义为纯虚函数,实际上是将这个类定义为抽象类,不能实例化对象。(与第5点结合) 5) 纯虚函数通常没有定义体,但也完全可以拥有。 6) 析构函数可以是纯虚的,但纯虚析构函数必须有定义体,因为析构函数的调用是在子类中隐含的。 7) 非纯的虚函数必须有定义体,不然是一个错误。 8) 派生类的override虚函数定义必须和父类完全一致。除了一个特例,如果父类中返回值是一个指针或引用,子类override时可以返回这个指针(或引用)的派生。例如,在上面的例子中,在Base中定义了 virtual Base* clone(); 在Derived中可以定义为 virtual Derived* clone()。可以看到,这种放松对于Clone模式是非常有用的。 9)基类private纯虚函数:在C++中virtual表示多态,public

C++ 进阶之二:构造和继承

我与影子孤独终老i 提交于 2019-12-10 07:32:34
以同样的顺序定义和初始化成员变量 原因:C++ 为了确保销毁成员的顺序是唯一的,要求初始化成员的顺序也唯一。那根据什么顺序去初始化呢,就根据成员变量在类中定义的顺序。 在构造函数中用初始化代替赋值 原因:如果不这么做,会对成员变量调用默认构造函数,然后在初始化的时候,再次调用赋值操作。但这两个步骤,可以通过初始化中直接调用成员的赋值构造函数一步实现。 避免在构造函数和析构函数中调用虚拟函数 因为: 在派生对象的成员还没有被初始化的时候就调用其成员函数很可能产生意想不到的混乱。在基类的构造期间,没有办法说清楚到底基本是一个独立的对象还是其他派生类的基类部分。 将基类的析构函数设置为公共、虚拟的或者保护、非虚拟的 因为: 如果需要通过基类指针直接析构派生类对象:派生类就需要动态地继承基类的析构函数,这就要求需要把基类的析构函数设置为公共的、虚拟的。 如果不需要通过基类指针直接析构派生类对象:那基类的析构函数不需要被子类调用,因而可以设置为保护的、非虚拟的。 来源: 51CTO 作者: 存储之厨 链接: https://blog.51cto.com/xiamachao/2457334

C++之多态性与虚函数

北城以北 提交于 2019-12-10 04:03:01
  面向对象程序设计中的多态性是指向不同的对象发送同一个消息,不同对象对应同一消息产生不同行为。在程序中消息就是调用函数,不同的行为就是指不同的实现方法,即执行不同的函数体。也可以这样说就是实现了“一个接口,多种方法”。   从实现的角度来讲,多态可以分为两类:编译时的多态性和运行时的多态性。前者是通过静态联编来实现的,比如C++中通过函数的重载和运算符的重载。后者则是通过动态联编来实现的,在C++中运行时的多态性主要是通过虚函数来实现的,也正是今天我们要讲的主要内容。   1.不过在说虚函数之前,我想先介绍一个有关于基类与派生类对象之间的复制兼容关系的内容。它也是之后学习虚函数的基础。我们有时候会把整型数据赋值给双精度类型的变量。在赋值之前,先把整形数据转换为双精度的,在把它赋值给双精度类型的变量。这种不同类型数据之间的自动转换和赋值,称为赋值兼容。同样的,在基类和派生类之间也存在着赋值兼容关系,它是指需要基类对象的任何地方都可以使用 公有 派生类对象来代替。为什么只有公有继承的才可以呢,因为在公有继承中派生类保留了基类中除了构造和析构之外的所有成员,基类的公有或保护成员的访问权限都按原样保留下来,在派生类外可以调用基类的公有函数来访问基类的私有成员。因此基类能实现的功能,派生类也可以。   那么它们具体是如何体现的呢 ?(1)派生类对象直接向基类赋值,赋值效果

将构造函数,析构函数声明为私有和保护的,那么对象如何创建

∥☆過路亽.° 提交于 2019-12-10 01:39:07
已经不能从外部调用构造函数了,但是对象必须被构造,应该如何解决,麻烦大家帮忙说明,关于构造,析构函数声明为私有和保护时的用法??? 提出这个问题,说明你已经对c++有所思考了。 从语法上来讲,一个函数被声明为protected或者private,那么这个函数就不能从“外部”直接被调用了。 对于protected的函数,子类的“内部”的其他函数可以调用之。 而对于private的函数,只能被本类“内部”的其他函数说调用。 语法上就是这么规定的,你肯定也知道的咯。 那么为什么有时候将构造函数或者析构函数声明为protected的或者private的? 通常使用的场景如下: 1。如果你不想让外面的用户直接构造一个类(假设这个类的名字为A)的对象,而希望用户只能构造这个类A的子类,那你就可以将类A的构造函数/析构函数声明为protected,而将类A的子类的构造函数/析构函数声明为public。例如: 来源: https://www.cnblogs.com/hshy/p/12013602.html

C++ virtual 析构函数

落花浮王杯 提交于 2019-12-09 22:48:11
C++中虚析构函数的作用 我们知道,用C++开发的时候,用来做基类的类的析构函数一般都是虚函数。可是,为什么要这样做呢?下面用一个小例子来说明: 有下面的两个类: [cpp] view plain copy #include <iostream> using namespace std; class ClxBase { public: ClxBase() {}; virtual ~ClxBase() {cout<<"AAA"<<endl;}; 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; }; }; int main() { ClxBase *pTest = new ClxDerived; pTest->DoSomething

构造函数与虚构函数

倖福魔咒の 提交于 2019-12-09 22:27:45
1、构造函数和析构函数为什么没有返回值? 构造函数和析构函数是两个非常特殊的函数:它们没有返回值。这与返回值为void的函数显然不同,后者虽然也不返回任何值,但还可以让它做点别的事情,而构造函数和析构函数则不允许。 在程序中创建和消除一个对象的行为非常特殊,就像出生和死亡,而且 总是由编译器来调用这些函数以确保它们被执行 。如果它们有返回值,要么编译器必须知道如何处理返回值,要么就只能由客户程序员自己来显式的调用构造函数与析构函数,这样一来,安全性就被破坏了。另外, 析构函数不带任何参数 ,因为析构不需任何选项。 如果允许构造函数有返回值,在某此情况下,会引起歧义。如下两个例子 class C { public: C(): x(0) { } C(int i): x(i) { } private: int x; }; 如果C的构造函数可以有返回值,比如: int:int C():x(0) { return 1; } //1表示构造成功,0表示失败 那么下列代码会发生什么事呢? C c = C(); //此时c.x == 1 分析: 很明显,C()调用了C的无参数构造函数,该构造函数返回int值1。 按照C++的规定,C c = C();是用默认构造函数创建一个临时对象,并用这个临时对象初始化c,此时,c.x的值应该是0。 但是,如果C::C()有返回值,并且返回了1(为了表示成功)

C++中将构造函数和析构函数定义为private的用意

梦想的初衷 提交于 2019-12-09 20:37:43
很多情况下要求当前的程序中只有一个object。例如一个程序只有一个和数据库的连接,只有一个鼠标的object。通常我们都将构造函数的声明置于public区段,假如我们将 其放入private区段中会发生什么样的后果?这意味着什么? 当我们在程序中声明一个对象时,编译器为调用构造函数(如果有的话),而这个调用将通常是外部的,也就是说它不属于class对象本身的调用,假如构造函数是私有的, 由于在class外部不允许访问私有成员,所以这将导致编译出错。 然而,对于class本身,可以利用它的static公有成员,因为它们独立于class对象之外,不必产生对象也可以使用它们。 此时因为构造函数被class私有化,所以我们要创建出对象,就必须能够访问到class的私有域;这一点只有class的成员可以做得到;但在我们建构出其对象之前,怎么能利用它 的成员呢?static公有成员,它是独立于class对象而存在的,“我们”可以访问得到。假如在某个static函数中创建了该class的对象,并以引用或者指针的形式将其返回(这里不 以对象返回,主要是构造函数是私有的,外部不能创建临时对象),就获得了这个对象的使用权。 下面是例子: class OnlyHeapClass { public: static OnlyHeapClass* GetInstance() { //

何时使用虚拟析构函数?

北战南征 提交于 2019-12-09 11:21:10
我对大多数面向对象理论有扎实的了解,但令我困惑的一件事是虚拟析构函数。 我以为无论链中的每个对象是什么,析构函数总是被调用。 您打算何时将它们虚拟化?为什么? #1楼 我喜欢考虑接口和接口的实现。 在C ++中,接口是纯虚拟类。 析构函数是接口的一部分,有望实现。 因此,析构函数应该是纯虚拟的。 构造函数呢? 构造函数实际上不是接口的一部分,因为对象总是显式实例化的。 #2楼 虚拟构造函数是不可能的,但虚拟析构函数是可能的。 让我们尝试一下... #include <iostream> using namespace std; class Base { public: Base(){ cout << "Base Constructor Called\n"; } ~Base(){ cout << "Base Destructor called\n"; } }; class Derived1: public Base { public: Derived1(){ cout << "Derived constructor called\n"; } ~Derived1(){ cout << "Derived destructor called\n"; } }; int main() { Base *b = new Derived1(); delete b; } 上面的代码输出以下内容:

何时使用虚拟析构函数?

旧时模样 提交于 2019-12-08 14:23:28
我对大多数面向对象理论有扎实的了解,但令我困惑的一件事是虚拟析构函数。 我以为无论链中的每个对象是什么,析构函数总是被调用。 您打算何时将它们虚拟化?为什么? #1楼 我喜欢考虑接口和接口的实现。 在C ++中,接口是纯虚拟类。 析构函数是接口的一部分,有望实现。 因此,析构函数应该是纯虚拟的。 构造函数呢? 构造函数实际上不是接口的一部分,因为对象总是显式实例化的。 #2楼 虚拟构造函数是不可能的,但虚拟析构函数是可能的。 让我们尝试一下... #include <iostream> using namespace std; class Base { public: Base(){ cout << "Base Constructor Called\n"; } ~Base(){ cout << "Base Destructor called\n"; } }; class Derived1: public Base { public: Derived1(){ cout << "Derived constructor called\n"; } ~Derived1(){ cout << "Derived destructor called\n"; } }; int main() { Base *b = new Derived1(); delete b; } 上面的代码输出以下内容:

Effective C++:unio

守給你的承諾、 提交于 2019-12-07 19:41:36
联合是一种特殊的类。 一个union可以有多个数据成员,但是在任意时刻只有一个数据成员可以有值。当我们给union中的某个成员赋值的之后,该union中的其他成员变成了未定义的状态。 需要特别注意的是: 1,当给一个union类型分配空间的时候至少要分配能容纳它的最大的数据成员的空间。 2,C++11新标准中规定除了内置类型(int, double...),带有构造函数和析构函数的类型也可以作为union的成员类型。 3,union也可以为其成员指定public, private, ptorected等权限标记符。但是默认情况下都是public的。 4,union不可以继承自其他class,也不能被其他class继承. 5,union类型编译器是不会自动合成析构函数的我们可以通过显式的写出来来保证 非POD和内置类型 的析构函数被调用. 使用union在编译时间做big-endian和little-endian的判断: #include <iostream> #include <vector> #include <cstdint> //static union { std::int32_t mylong; char c[4]; } endian_test = { 0x623f3f6c }; union endian_test { std::int32_t mylong; char