一、几种继承方式
二、举例与格式
#include<iostream>
using namespace std;
class A
{
public:
A(int _a)
:a(_a)
{
}
int geta()
{
return a;
}
private:
int a;
};
class B :public A//继承格式
{
public:
B(int _b,int _a)//派生类构造函数先写基类的构造参数,再写自己的参数
:A(_a)
,b(_b)
{
}
int getb()
{
return b;
}
private:
int b;
};
三、注意事项
(1)三种继承方式
1.基类的private成员,在之后无论什么派生方式都是不可反问的内容。
2.对于 基类+一层派生 这种结构,private与protected这两种派生方式没有区别,都是派生类中可以访问基类中的非private对象,派生类对象不能访问基类的任何成员;而public继承则在派生类中和派生类对象都可以访问基类的非private成员。
3.对于 基类+一层派生+多层派生 protected与private才用于调整继承的关系,以private继承的二层无法访问基类,而以protected继承的则可以。
4.一般派生类对象的成员变量是从新开辟空间的,和基类成员变量使用不同的空间,不是拷贝的关系
(2)派生类的同名隐藏规则
#include<iostream>
using namespace std;
class A
{
public:
A(int _a)
:a(_a)
{
}
int geta()//与派生类同名
{
return a;
}
private:
int a;
};
class B :public A
{
public:
B(int _a,int _b)
:A(_a)
,b(_b)
{
}
int geta()//与基类同名
{
return b;
}
private:
int b;
};
int main()
{
B b(1, 2);//A中为1,B中为2
cout << b.geta() << endl;//同名隐藏,优先调用B的geta函数
cout << b.A::geta() << endl;//强制调用A的geta函数
return 0;
}
(3)赋值兼容规则
1.第一条
class A
{
public:
A(int _a)
:a(_a)
{
}
int geta()
{
return a;
}
private:
int a;
};
class B :public A
{
public:
B(int _a,int _b)
:A(_a)
,b(_b)
{
}
int getb()
{
return b;
}
private:
int b;
};
int main()
{
A a(3);
B b(1, 2);
a = b;//派生类对象可以赋值给基类对象
cout << a.geta() << endl;//改变了基类的成员变量的值(3变为1)
return 0;
}
2.第二条
class A
{
public:
A(int _a)
:a(_a)
{
}
void display()
{
cout << 'A' << endl;
}
private:
int a;
};
class B :public A
{
public:
B(int _a,int _b)
:A(_a)
,b(_b)
{
}
void display()
{
cout << 'B' << endl;
}
private:
int b;
};
class C :public B
{
public:
C(int _a, int _b,int _c)
:B(_a,_b)
, c(_c)
{
}
void display()
{
cout << 'C' << endl;
}
private:
int c;
};
void fun(A& p)
{
p.display();
}
int main()
{
A a(1);
B b(2, 3);
C c(4, 5, 6);
fun(a);//调用A的display
fun(b);//调用A的display
fun(c);//调用A的display
return 0;
}
3.第三条
class A
{
public:
A(int _a)
:a(_a)
{
}
void display()
{
cout << 'A' << endl;
}
private:
int a;
};
class B :public A
{
public:
B(int _a,int _b)
:A(_a)
,b(_b)
{
}
void display()
{
cout << 'B' << endl;
}
private:
int b;
};
class C :public B
{
public:
C(int _a, int _b,int _c)
:B(_a,_b)
, c(_c)
{
}
void display()
{
cout << 'C' << endl;
}
private:
int c;
};
void fun(A* p)
{
p->display();
}
int main()
{
A a(1);
B b(2, 3);
C c(4, 5, 6);
fun(&a);//调用A的display
fun(&b);//调用A的display
fun(&c);//调用A的display
return 0;
}
(4)派生类构造函数
基类的构造函数不会被继承,派生类要自己写构造函数,定义构造函数时,需要对本类中新增成员进行初始化,对继承来的基类成员的初始化,是自动调用基类构造函数完成的。 派生类的构造函数需要给基类的构造函数传递参数。
class A
{
public:
A(int _a)
:a(_a)
{
}
private:
int a;
};
class B :public A
{
public:
B(int _a,int _b)//派生类构造函数先传基类的参数,再传自己的参数
:A(_a)
,b(_b)
{
}
private:
int b;
};
class C :public B
{
public:
C(int _a, int _b,int _c)//派生类构造函数先传基类的参数,再传自己的参数
:B(_a,_b)
, c(_c)
{
}
private:
int c;
};
关于构造函数的执行顺序:
#include <iostream>
using namespace std;
class Base1
{ // 基类Base1,构造函数有参数
public:
Base1(int i)
{
cout << "Constructing Base1 " << i << endl;
}
};
class Base2
{ // 基类Base2,构造函数有参数
public:
Base2(int j)
{
cout << "Constructing Base2 " << j << endl;
}
};
class Base3 { // 基类Base3,构造函数无参数
public:
Base3() {
cout << "Constructing Base3 *" << endl;
}
};
class Derived : public Base2, public Base1, public Base3
{
public:
Derived(int a, int b, int c, int d) : Base1(a), member2(d), member1(c), Base2(b)
{
// 注意基类名的个数与顺序,注意成员对象名的个数与顺序,此处的次序与构造函数的执行次序无关
}
private:
Base1 member1;
Base2 member2;
Base3 member3;
};
int main()
{
Derived obj(1, 2, 3, 4);
return 0;
}
(5)派生类的拷贝构造函数
#include <iostream>
using namespace std;
class Base1
{
public:
Base1(int i)
{
cout << "Constructing Base1 " << i << endl;
value1 = i;
}
// 基类的拷贝构造函数
Base1(const Base1& other)
{
cout << "Copy constructing Base1 " << other.value1 << endl;
value1 = other.value1;
}
protected:
int value1;
};
class Base2
{
public:
Base2(int j)
{
cout << "Constructing Base2 " << j << endl;
value2 = j;
}
// 基类的拷贝构造函数
Base2(const Base2& other)
{
cout << "Copy constructing Base2 " << other.value2 << endl;
value2 = other.value2;
}
protected:
int value2;
};
class Base3
{
public:
Base3()
{
cout << "Constructing Base3 *" << endl;
value3 = 0;
}
// 基类的拷贝构造函数
Base3(const Base3& other)
{
cout << "Copy constructing Base3 *" << endl;
value3 = other.value3;
}
protected:
int value3;
};
class Derived : public Base2, public Base1, public Base3 //注意继承顺序是2,1,3
{
public:
Derived(int a, int b, int c, int d)
: Base1(a)
, member2(d)
, member1(c)
, Base2(b)
{
cout << "Constructing Derived" << endl;
value4 = d;
}
// 派生类的拷贝构造函数
Derived(const Derived& other)
: Base2(other) // 显式调用基类的拷贝构造函数
, Base1(other) // 按照继承顺序调用(2,1,3)
, Base3(other)
, member1(other.member1) // 复制成员对象
, member2(other.member2)
, member3(other.member3)
{
cout << "Copy constructing Derived" << endl;
value4 = other.value4; // 复制派生类自身的成员
}
private:
Base1 member1;
Base2 member2;
Base3 member3;
int value4;
};
int main() {
Derived obj1(1, 2, 3, 4);
cout << "\nCreating obj2 as a copy of obj1:\n";
Derived obj2(obj1); // 调用拷贝构造函数
return 0;
}
(6)派生类的析构函数
派生类的析构函数一般用基类的就行了,如果自己新开了空间就自己写。此外,析构函数的调用次序与构造函数相反。
(7)二义性问题
此外还会产生内存冗余问题
#include <iostream>
using namespace std;
class Base0
{ // 定义基类Base0
public:
int var0;
void fun0()
{
cout << "Member of Base0" << endl;
}
};
class Base1 : public Base0
{ // 定义派生类Base1
public:
// 新增外部接口
int var1;
};
class Base2 : public Base0
{ // 定义派生类Base2
public:
// 新增外部接口
int var2;
};
class Derived : public Base1, public Base2
{
public:
int var;
void fun()
{
cout << "Member of Derived" << endl;
}
};
int main()
{ // 程序主函数
Derived d;
d.Base1::var0 = 2;
d.Base1::fun0();
d.Base2::var0 = 3;
d.Base2::fun0();
return 0;
}
(8)虚基类
将其共同基类设置为虚基类。这时,从不同路径继承来的同名数据成 员在内存中就只有一个拷贝,同一个函数名也只有一个映射,也可解决同名成员的唯一标识问题。
虚基类的成员b,与其派生类共同维护的是同一块空间。
注意: 为了保证虚基类在派生类中只继承一次,应当在该基类的所有直接派生类中声明为虚基类。否则仍然会出现对基类的多次继承。如图所示的那样,在派生类B和C中将类A声明为虚基类,而在派生类D中没有将类A声明为虚基类,则在派生类E中,虽然从类B和C路径派生的部分只保留一份基类成员,但从类D路径派生的部分还保留一份基类成员。
#include <iostream>
using namespace std;
class Base0
{
public:
Base0(int var) : var0(var)
{
cout << "Base0" << endl;
}
void fun0()
{
cout << "Member of Base0" << endl;
}
int var0;
};
class Base1 : virtual public Base0
{
public:
Base1(int var) : Base0(var)
{
}
int var1;
};
class Base2 : virtual public Base0
{
public:
Base2(int var) : Base0(var)
{
}
int var2;
};
class Derived : public Base1, public Base2
{
public:
Derived(int var)
: Base0(var)
, Base1(var)
, Base2(var)
{
}
void fun()
{
cout << "Member of Derived" << endl;
}
int var;
};
int main()
{
Derived d(1);
d.var0 = 2;
d.fun0();
return 0;
}