类中默认成员函数的继承方法
一、什么是继承?
它允许程序员在保持原有类特性的基础上进行扩展,增加功能。这样产生新的类,成为派生类。简单来说,就是父子继承关系,你从你父亲继承了某些东西,而你在你父亲的基础上又扩充了相关的功能特性,构成了你自己。你自己就是一个子类,也就是派生类。
在对派生类做介绍之前,先了解一下继承权限的问题。简单给大家做一个总结。
继承分为三类:公有继承(public)、保护继承(protected)、私有继承(private)。对于基类中的私有成员,三种继承方式都不可见。以下三种继承是针对除私有成员外,对于公有继承,所有成员的特性不变。对于保护继承,所有成员特性变为保护方式。对于私有继承,所有成员特性变为私有方式。
在这里需要注意:使用关键字class时默认的继承方式是private,使用struct时默认的继承方式是public。
二、对于类中的默认的成员函数,子类会继承父类中的吗?
1.构造函数
class Base
{
public:
Base()
{
cout << "Base::Base()" << endl;
}
int _b;
};
class Derived :public Base
{
public:
int _d;
};
int main(){
Derived d;
d._b = 1;
d._d = 2;
return 0;
}
1.基类中有缺省的构造函数,派生类就会调用默认的构造函数。
2.基类没有定义构造函数,则派生类也可以不用定义,全部使用缺省构造函数。
将上面的基类改为如下
class Base
{
public:
Base(int i)
:_b(i)
{
cout << "Base::Base()" << endl;
}
int _b;
};
编译上述的代码,显示Derived类中没有可用的构造函数,这说明,
3.当基类中有带参数列表的构造函数时,派生类必须定义构造函数,且在初始化列表中显示的给出基类名和参数列表,
如下
class Base
{
public:
Base(int i)
:_b(i)
{
cout << "Base::Base()" << endl;
}
int _b;
};
class Derived :public Base
{
public:
Derived()
:Base(1)
{
cout << "Derived::Base()" << endl;
}
int _d;
};
知道了派生类的构造函数的具体定义,在来看一下派生类的构造函数的调用次序问题
在派生类中会先调用派生类的构造函数,但是在派生类的初始化链表部分,就会转去调用基类的构造函数,所以先初始化的是基类,然后再去初始化派生类。可以用反汇编代码来看一下派生类的构造函数
可见在派生类中call即调用了Base的构造函数。
2.拷贝构造函数
class Base
{
public:
Base(int i)
:_b(i)
{
cout << "Base::Base()" << endl;
}
Base(const Base& b)
{
_b = b._b;
}
int _b;
};
class Derived :public Base
{
public:
Derived()
:Base(1)
{
cout << "Derived::Derived()" << endl;
}
int _d;
};
#endif
int main(){
Derived d1;
Derived d2(d1);
return 0;
}
用内存窗口看看d2是否正确拷贝d1
上边是d1的,下边是d2的,可以看出拷贝无误。
由此可以看出,1.基类没有定义拷贝构造函数,则派生类也可以不用定义,全部使用默认拷贝构造函数(派生类自己的数据不涉及深拷贝)。
2.当基类中有定义的拷贝构造函数时,派生类也可以使用默认的拷贝构造函数(派生类自己的数据不涉及深拷贝)。
这时不同于构造函数的是,派生类默认的构造函数在转去调用基类中的构造函数时,不会提供基类中的形参列表的数据,这时编译器就不会找到合适的构造函数。 而拷贝构造函数是只需提供一个派生类的对象(包含基类的数据和自己的数据), 在派生类中调用拷贝构造函数时,会转去调用基类中的拷贝构造函数,这时将基类的数据先去拷贝一份,在根据编译器合成的默认拷贝构造函数,将派生类自己的也拷有人会说深拷贝的时候会出错,这时要考略
3. 那如果是深拷贝呢????分为两种情况。
派生类自己的数据不包含深拷贝,这时如果基类中是深拷贝,有问题吗????当然是没有问题的。这是因为你已经在基类中定义好了基类的拷贝构造函数,你直接去调用而已,所以基类中的数据的地址是两份的。
派生类自己的数据是深拷贝,这是你必须显示定义派生类的拷贝构造函数,否则派生类自己的指针变量就会出现共用同一块地址空间而导致的析构时,一块地址空间被连续释放多次。
3.析构函数
class Base
{
public:
Base(int i)
:_b(i)
{
cout << "Base::Base()" << endl;
}
Base(const Base& b)
{
_b = b._b;
cout << "Base::Base(const Base& b)" << endl;
}
~Base()
{
cout << "Base::~Base()" << endl;
}
int _b;
};
class Derived :public Base
{
public:
Derived(int d)
:Base(1),
_d(d)
{
cout << "Derived::Base()" << endl;
}
int _d;
};
1.基类没有定义析构函数,则派生类也可以不用定义,全部使用默认析构函数(派生类自己的数据不涉及深拷贝)。
2.当基类中有定义的析构函数时,派生类也可以使用默认的拷贝构造函数(派生类自己的数据不涉及深拷贝)。
3.如果派生类自己包含深拷贝,则析构函数必须显示的给出来,否则设计深拷贝的地址空间释放不了。思想和拷贝构造函数一样。
4.赋值操作符重载 ------->和拷贝构造函数/析构函数一样