构造方法用来初始化类的对象,与父类的其它成员不同,它不能被子类继承(子类可以继承父类所有的成员变量和成员方法,但不继承父类的构造方法)。因此,在创建子类对象时,为了初始化从父类继承来的数据成员,系统需要调用其父类的构造方法。
如果没有显式的构造函数,编译器会给一个默认的构造函数,并且该默认的构造函数仅仅在没有显式地声明构造函数情况下创建。
构造原则如下:
1. 如果子类没有定义构造方法,则调用父类的无参数的构造方法。
2. 如果子类定义了构造方法,不论是无参数还是带参数,在创建子类的对象的时候,首先执行父类无参数的构造方法,然后执行自己的构造方法。
3. 在创建子类对象时候,如果子类的构造函数没有显示调用父类的构造函数,则会调用父类的默认无参构造函数。
4. 在创建子类对象时候,如果子类的构造函数没有显示调用父类的构造函数且父类自己提供了无参构造函数,则会调用父类自己的无参构造函数。
5. 在创建子类对象时候,如果子类的构造函数没有显示调用父类的构造函数且父类只定义了自己的有参构造函数,则会出错(如果父类只有有参数的构造方法,则子类必须显示调用此带参构造方法)。
6. 如果子类调用父类带参数的构造方法,需要用初始化父类成员对象的方式,比如:
#include <iostream.h>
class animal
{
public:
animal(int height, int weight)
{
cout<<"animal construct"<<endl;
}
…
};
class fish:public animal
{
public:
fish():animal(400,300)
{
cout<<"fish construct"<<endl;
}
…
};
void main()
{
fish fh;
}
在fish类的构造函数后,加一个冒号(:),然后加上父类的带参数的构造函数。这样,在子类的构造函数被调用时,系统就会去调用父类的带参数的构造函数去构造对象。
子类可以继承父类所有的成员变量和成员方法,但不继承父类的构造方法,由于对成员变量的初始化是在构造方法中实现的,所以在创建子类对象时,为了初始化从父类继承来的数据成员,系统需要调用其父类的构造方法:
在创建子类对象时,若子类没有定义构造函数,则默认调用父类的无参数(有参则编译报错)的构造方法:
#include<iostream>
using namespace std;
class A{
public:
string name;
public:
A(){
name = "hello";
}
};
class B : public A{
};
int main(){
B me;
cout << me.name << endl;//若name的作用域符号为private或protect,此处都无法进行访问
return 0;
}
在创建子类对象时,若子类定义的构造函数没有显示调用父类的构造函数且父类的构造函数为无参构造函数(含无参构造函数,不一定仅一个无参构造函数),则默认调用父类无参构造函数:
#include<iostream>
using namespace std;
class A{
public:
string name;
public:
A(){
name = "hello";
}
};
class B : public A{
public:
B(){
}
};
int main(){
B me;
cout << me.name << endl;//若name的作用域符号为private或protect,此处都无法进行访问
return 0;
}
在创建子类对象时,父类全为有参构造函数,如果子类的构造函数没有显示调用父类的有参构造函数,则编译报错:
在创建子类对象时,必须先调用父类构造器,对于父类有参构造,显式调用的目的在于明确父类的构造参数的传入,然后再进行子类构造
父类有参构造参数在子类构造中以定量形式传入,子类构造可以为无参构造(在创建子类对象时不用传入参数到父类构造器)
#include<iostream>
using namespace std;
class animal
{
public:
int height;
int weight;
animal(int height,int weight) //带参的构造函数
{
this->height=height;
this->weight=weight;
cout<<"animal的带参构造函数被调用"<<endl;
}
virtual ~animal()
{
cout<<"animal的析构函数被调用"<<endl;
}
};
class fish:public animal
{
public:
fish():animal(100, 50) //显示调用父类的构造函数
{
cout<<"fish的构造函数被调用"<<endl;
}
virtual ~fish()
{
cout<<"fish的析构函数被调用"<<endl;
}
};
int main(){
fish a_fish;
cout << a_fish.height << endl;
return 0;
}
PS:fish()::animal(100, 50); 创建子类对象:fish a_fish;
父类有参构造参数在子类构造中为变量,必须由外部传入参数,子类构造必须为有参构造,由子类创建时构造函数的参数先传入基类构造函数构造基类,进而构造子类;
#include<iostream>
using namespace std;
class animal
{
public:
int height;
int weight;
animal(int height,int weight) //带参的构造函数
{
this->height=height;
this->weight=weight;
cout<<"animal的带参构造函数被调用"<<endl;
}
virtual ~animal()
{
cout<<"animal的析构函数被调用"<<endl;
}
};
class fish:public animal
{
public:
fish(int height, int weight):animal(height, weight) //显示调用父类的构造函数
{
cout<<"fish的构造函数被调用"<<endl;
}
virtual ~fish()
{
cout<<"fish的析构函数被调用"<<endl;
}
};
int main(){
fish a_fish(500, 300);
cout << a_fish.height << endl;
return 0;
}
PS: fish(int height, int weight)::animal( height, weight ) 此处animal的传入参数必须为基类构造animal函数的形参; fish a_fish(100, 50)
当调用fish a_fish(100,50),把参数100,50同时传递给子类构造器与父类构造器,赋值动作实际上发生在父类构造器中,这也是为什么子类fish的构造器中关于对height与weight的处理语句为空的缘故,因为其都在父类构造器中完成了。