文章目录
继承
从一个类派生出另一个类时,原始类称为基类,继承类称为派生类。
派生类:
特点:
派生类继承了基类的实现
派生类继承了基类的方法
派生类需要自己的构造函数
派生类可以根据需要添加额外的数据成员和成员函数。
派生类构造函数要点:
首先创建基类对象
派生类构造函数应通过成员初始化列表将基类信息传递给构造函数
派生类构造函数应初始化派生类新增的数据成员
派生类和基类的关系
派生类不可以直接访问基类的私有成员,必须通过基类非私有方法进行访问
创建派生类对象时,程序首先创建基类对象,也就是说,程序必须在进入派生类之前创建基类
继承方式:
公共继承:
可以访问父类中public和protected的属性,不可访问private的对象
父类中公共权限的内容,在子类中依然是公共权限的;
父类中保护权限的内容,在子类中依然是保护权限的;
不可访问父类私有权限的内容。
保护继承:
可以访问父类中public和protected的属性,不可访问private的对象
父类中公共权限的内容,在子类中是保护权限的;
父类中保护权限的内容,在子类中依然是保护权限的;
不可访问父类私有权限的内容。
私有继承:
可以访问父类中public和protected的属性,不可访问private的对象
父类中公共权限的内容,在子类中是私有权限的内容
父类中保护权限的内容,在子类中是私有权限的内容
不可访问父类私有权限的内容
父类中所有非静态成员都会被子类继承,即使私有成员无法访问,但也是会被子类继承下去。
class Father
{
public:
int a;
protected:
int b;
private:
int c;
};
class childA :public Father
{
public:
void func()
{
a = 100; //a为public权限
b = 100; //b为protected权限
//父类私有成员c 不可访问
}
};
class childB :protected Father
{
public:
void func()
{
a = 100; //a为protected权限
b = 100; //b为protected权限
//父类私有成员c 不可访问
}
};
class childC :private Father
{
public:
void func()
{
a = 100; //a为private权限
b = 100; //b为private权限
//父类私有成员c 不可访问
}
};
int main()
{
childA a;
//childA类继承Father类,childA 中没有新成员,Father中有三个int型成员
//3*sizeof(int)
cout << "childA的大小为:" << sizeof(a) << endl;
return 0;
}
运行结果:
继承中的构造和析构顺序
class Father
{
public:
Father()
{
cout << "父类构造函数被调用" << endl;
}
~Father()
{
cout << "父类析构函数被调用" << endl;
}
};
class childA :public Father
{
public:
childA()
{
cout << "子类构造函数被调用" << endl;
}
~childA()
{
cout << "子类析构函数被调用" << endl;
}
};
int main()
{
childA a;
return 0;
}
运行结果:
调用子类对象时,先调用父类构造函数,再调用子类构造函数,结束时,先调用子类的析构函数,再调用父类的析构函数,也就是说,先创建父类,再创建子类,销毁时,先销毁子类,再销毁父类。
类似于栈的后进先出的顺序,先被调用构造函数的后被调用析构函数。
子类和父类中同名成员处理
同名属性
如果子类和父类中有成员重名,子类对象访问子类重名成员直接访问即可,若是访问父类重名成员,需要添加作用域。
class Father
{
public :
Father()
{
a = 100;
}
int a;
};
class Child :public Father
{
public :
Child()
{
a = 200;
}
int a;
};
int main()
{
Child child;
cout << "子类中的a ="<<child.a << endl;
cout << "父类中的a =" << child.Father::a << endl;
return 0;
}
同名函数
访问方式与同名成员访问方式相同。
class Father
{
public :
Father()
{
a = 100;
}
int a;
void test()
{
cout << "父类同名函数调用" << endl;
}
};
class Child :public Father
{
public :
Child()
{
a = 200;
}
int a;
void test()
{
cout << "子类同名函数调用" << endl;
}
};
int main()
{
Child child;
child.test();
child.Father::test();
return 0;
}
父类中的同名函数如果出现重载,在子类对象中调用父类中重载的同名函数时不可以直接写函数名(参数),需要在前面加上作用域再传参数。
class Father
{
public :
Father()
{
a = 100;
}
int a;
void test()
{
cout << "父类同名函数调用" << endl;
}
void test(int a)
{
cout << "父类同名重载函数被调用" << endl;
}
};
class Child :public Father
{
public :
Child()
{
a = 200;
}
int a;
void test()
{
cout << "子类同名函数调用" << endl;
}
};
int main()
{
Child child;
child.test();
//下面这种写法会报错
//child.test(10);
child.Father::test(10);
return 0;
}
同名静态成员访问
静态成语访问同非静态成员访问方式相同
- 子类同名静态成员直接访问
- 父类同名静态成员访问需要添加作用域
- 也可以不创建对象直接访问静态成员,类名::成员名
多继承语法
在C++中,允许一个类继承好几个类,使用“,”分割继承的父类
当父类中出现成员重名现象,需要加上作用域以示区分。
class Father1
{
public :
Father1()
{
a = 100;
}
int a;
};
class Father2
{
public :
Father2()
{
b = 200;
}
int b;
};
class child :public Father1, public Father2
{
public :
child()
{
c = 300;
}
int c;
};
int main()
{
child d;
cout << "访问Father1成员a = " << d.a << endl;
cout << "访问Father2成员b =" <<d.b << endl;
cout << "访问child成员c =" << d.c << endl;
}