C++部分——C++面向对象(3)

1.构造函数explicit与普通构造函数有什么区别?

(explicit构造函数的作用)
explicit构造函数是用来防止隐式转换的。
代码如下:

class Test1
{
public:
    Test1(int n){num=n};//普通构造函数
private:
    int num;
};

class Test2
{
public:
    explicit Test2(int n){num=n;}//explicit(显式)构造函数
private:
    int num;
};

int main()
{
    Test1 t1=12;//隐式调用其构造函数,成功
    Test2 t2=12;//编译错误,不能隐式调用其构造函数
    Test2 t3(12);//显示调用成功
    return 0;

Test1的构造函数带一个int型的参数,代码Test1 t1=12;会隐式转换成调用Test1的这个构造函数。而Test2的构造函数被声明为explicit(显式),这表示不能通过隐式转换来调用这个构造函数,因此Test2 t2=12;会出现编译错误。
所以,普通构造函数能够被隐式转换,而explicit构造函数只能显示调用。

2.explicit构造函数的作用

下面的程序f()被调用时,输出是什么?

#include<iostream>
#include<string>
using namespace std;

class Number
{
public:
    string type;
    Number():type("void"){}
    explicit Number(short):type("short");
    Number(int):type("int"){}
};

void Show(const Number& n){cout<<n.type;}

void main()
{
short s=42;
Show(s);
}

A.void
B.short
C.int
D.None of above
(1)Show(s)中的s为short类型,其值为42,因此首先检查参数为short的构造函数能否被隐式转换。由于代码第10行的构造函数被声明为显示调用(explicit),因此不能隐式转换。于是进行下一步。
(2)42自动转换为int类型。
(3)检查参数为int的构造函数能否被隐式转换。由于代码第11行参数为int的构造函数没有被声明为显示调用,因此调用此构造函数构造出一个临时对象。
(4)打印上一步临时对象的type成员,即“int”。

3.C++中虚析构函数的作用是什么

大家知道,析构函数时为了在对象不被使用之后释放它的资源,虚函数是为了实现多态。那么,把析构函数声明为virtual有什么作用呢?请看下面的代码:

#include<iostream>
using namespace std;

class Base
{
public:
    Base(){};//Base的构造函数
    ~Base()//Base的析构函数
    {
        cout<<"Output from the destructor of class Base!"<<endl;
    };
    void Dosomething()
    {
        cout<<"Do something in class Base!"<<endl;
    };
};

class  Derived:public Base
{
public:
    Derived() {};//Derived的构造函数
    ~Derived()//Derived的析构函数
    {
        cout<<"output from the destructor of class Derived!"<<endl;
    };
    void Dosomething()
    {
        cout<<"Do something in class Derived!"<<endl;
    };
};

int main()
{
    Derived *pTest1=new Derived();//Derived类的指针
    pTest1->Dosomething();
    delete pTest1;

    cout<<endl;

    Base *pTest2=new Derived();//Base类的指针
    pTest2->Dosomething();
    delete pTest2;

    return 0;
}

先看程序输出结果:

这里写图片描述

代码第36行,可以正常释放pTest1资源,而代码第42行没有正常释放pTest2的资源,因为从结果看,Derived的析构函数没有被调用。通常情况下,类的析构函数里面都是释放内存资源的,而析构函数不被调用的话就会造成内存泄漏。原因是指针pTest2是Base类型的指针,释放pTest2时只进行Base类的析构函数。在代码第8行前面加上virtual关键字,由于Base的析构函数时virtual的。就会先找到并执行Derived类的析构函数,然乎执行Base类的析构函数,资源正常释放,避免了内存泄漏。
因此,只有当一个类被用来作为基类的时候,才会把析构函数写成虚函数。

4.看代码写结构——析构函数的执行顺序

#include<iostream.h>
class A
{
private:
    int a;
public:
    A(int aa){a=aa;};
    ~A(){cout<<"Destructor A!"<<a<<endl;};
};

class B:public A
{
private:
    int b;
public:
    B(int aa=0,int bb=0):A(aa) {b=bb;};
    ~B(){cout<<"Destructor B!"<<b<<endl;};
};
void main()
{
    B obj1(5),obj2(6,7);
    return;
}

本题考查的是析构函数的执行顺序。析构函数的执行顺序与构造函数的执行顺序相反。
main()函数中定义了两个类B的对象,它们的基类是A。由于这两个对象都是栈中分配的,当main()函数退出时会发生析构,又因为obj1比obj2先声明,所以obj2先析构。它们析构的顺序是首先执行B的析构函数,然后执行A的析构函数。
输出结构如下:
这里写图片描述

7.复制构造函数是什么?什么是深复制和浅复制

(复制构造函数是什么?什么情况下用到它?什么是深复制什么是浅复制?)
复制构造函数是一种特殊的构造函数。它由编译器调用来完成一些基于同一类的其他对象的构件及初始化。
如果在类中没有显式地声明一个复制构造函数,那么,编译器会私下里制定一个函数来进行对象之间的位复制。这个隐含的复制构造函数简单地关联了所有的类成员。
浅复制是指让新旧两个对象指向同一外部的内容,而深复制是指为新对象制作了外部对象的独立复制

8.编译器与默认的copy constructor

(什么时候编译器会生成默认的copy constructor?如果已经写了一个构造函数,编译器还会生成copy constructor?)
如果用户没有自定义复制构造函数,并且代码中用到了复制构造函数,那么编译器就会生成默认的复制构造函数;但如果用户定义了复制构造函数,那么编译器就不会生成复制构造函数。
如果用户定义了一个构造函数,且不是复制构造函数,而此时在代码中用到了复制构造函数,那么编译器也还会生成默认的复制构造函数;如果没有使用,则编译器就不会生成默认的复制构造函数。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值