1.
但是一个派生类的指针可以安全地转化为一个基类的指针。这样删除一个基类的指针的时候,C++不管这个指针指向一个基类对象还是一个派生类的对象,调用的都是基类的析构函数而不是派生类的。如果你依赖于派生类的析构函数的代码来释放资源,而没有重载析构函数,那么会有资源泄漏。所以建议的方式是将析构函数声明为虚函数。
也就是delete a的时候,也会执行派生类的析构函数。
一个函数一旦声明为虚函数,那么不管你是否加上virtual 修饰符,它在所有派生类中都成为虚函数。但是由于理解明确起见,建议的方式还是加上virtual 修饰符。
----------------------------------------------------------------------------------------------------
2.
构造方法用来初始化类的对象,与父类的其它成员不同,它不能被子类继承
。因此,在创建子类对象时,为了初始化从父类继承来的数据成员,系统需要调用其父类的构造方法。
构造原则如下:
1.
如果子类没有定义构造方法,则调用父类的无参数的构造方法。
2.
如果子类定义了构造方法,不论是无参数还是带参数,在创建子类的对象的时候,首先执行父类无参数的构造方法
,然后执行自己的构造方法。
3. 在创建子类对象时候,如果子类的构造函数没有显示调用父类的构造函数,则会
调用父类的默认无参构造函数
。
4. 在创建子类对象时候,如果子类的构造函数没有显示调用父类的构造函数且
父类自己提供了无参构造函数
,则会调用父类自己的无参构造函数。
5. 在创建子类对象时候,如果子类的构造函数没有显示调用父类的构造函数且父类只定义了自己的有参构造函数,
则会出错
(
如果父类只有有参数的构造方法,则子类必须显示调用此带参构造方法
)。
6.
如果子类调用父类带参数的构造方法,需要用初始化父类成员对象的方式
#include <iostream>
using namespace std;
class animal
{
public:
animal()
{
cout << "asfasf" << endl;
}
animal(int height, int weight)
{
cout<<"animal construct"<<endl;
}
};
class fish:public animal
{
public:
int a;
fish():/*animal(400,300),*/ a(1)
{
cout<<a<<endl;
}
};
int main()
{
fish fh;
return 0;
}
----------------------------------------------------------------------------------------------------
3.
不能被派生类继承
1.构造函数
2.operator=()(
除了赋值运算符重载函数以外,所有的运算符重载函数都可以被派生类继承)
#include <iostream>
using namespace std;
class A1
{
public:
int operator=(int a)
{
return 8;
}
int operator+(int a)
{
return 9;
}
char* test(int a ,int b)
{
return "ads";
}
};
class B1 : public A1
{
public:
int operator-(int a)
{
return 7;
}
int test(int a)
{
return a;
}//overload
/*int operator=(int a)
{
return 9;
} */
};
int main()
{
B1 v;
cout << (v + 2) << endl; // OK, print 9
cout << (v - 2) << endl; // OK, print 7
cout << (v = 2) << endl; // Error, see below
cout << v.test(1) << endl;
return 0;
}
原因:
如果一个类没用定义 “赋值运算符重载函数”,在该类对象实例化的时候会自动生成一个默认的该函数。
B1会自动生成 :
B1& perator =(
const
B1& robj);
C++
标准规定:
如果派生类中声明的成员与基类的成员
同名
,那么,基类的成员会被覆盖,哪怕基类的成员与派生类的成员的数据类型和参数个数都完全不同。
所以父类的被子类的隐藏默认赋值运算符重载函数覆盖掉了。
---------------------------------------------------------------------------------------------------------------------------------
4.
继承有关的派生类拷贝构造函数
如:
class base {
public:
base(int initialvalue = 0): x(initialvalue) {}
base(const base& rhs): x(rhs.x) {}
private:
int x;
};
class derived: public base {
public:
derived(int initialvalue)
: base(initialvalue), y(initialvalue) {}
derived(const derived& rhs) // 错误的拷贝
: y(rhs.y) {} // 构造函数
private:
int y;
};
类derived展现了一个在所有c++环境下都会产生的bug:当derived的拷贝创建时,没有拷贝其基类部分。当然,这个derived对象的base部分还是创建了,但它是用base的缺省构造函数创建的,成员x被初始化为0(缺省构造函数的缺省参数值),而没有顾及被拷贝的对象的x值是多少!
为避免这个问题,derived的拷贝构造函数必须保证调用的是base的拷贝构造函数而不是base的缺省构造函数。这很容易做,只要在derived的拷贝构造函数的成员初始化列表里对base指定一个初始化值:
class derived: public base {
public:
derived(const derived& rhs): base(rhs), y(rhs.y) {}
...
};
现在,当用一个已有的同类型的对象来拷贝创建一个derived对象时,它的base部分也将被拷贝了。