c++继承相关知识总结
一 继承关系:public protected private
不矫情 直接贴代码 举例
代码主要从:
a. 基类成员对其对象的可见性: 只有public成员可以访问
b. 基类成员对派生类的可见性:
c. 基类成员对派生类对象的可见性:
a. 基类成员对其对象的可见性: 只有public成员可以访问
b. 基类成员对派生类的可见性:
c. 基类成员对派生类对象的可见性:
父类(基类)
class Base
{
public:
Base()
{
_pri = 1;
_pro = 2;
_pub = 3;
}
private:
int _pri;
protected:
int _pro;
public:
int _pub;
};
(1)public 继承方式
class Derived1 :public Base
{
public:
Derived1()
{
_d1_pri = 4;
_d1_pro = 5;
_d1_pub = 6;
}
void showd()
{
_pub = 0; // 仍为public成员
_pro = 2; // 仍为protected成员
//_pri = 3; // 父类私有成员对子类 不可见
}
private:
int _d1_pri;
protected:
int _d1_pro;
public:
int _d1_pub;
};
void TestPublic()
{
Base b;
b._pub = 1;
//b._pro = 2; // 父类对象不可访问父类保护成员
//b._pri = 3; // 父类对象不可访问父类私有成员
Derived1 d1;
d1._pub = 1; // 子类对象可以访问父类公有成员
//d1._pro = 2; //子类对象不可访问父类保护成员
//d1._pri = 3; // 子类对象不可访问父类私有成员
d1._d1_pub = 4;
}
(2) protected继承
// protected 保护继承
class Derived2 :protected Base
{
public:
Derived2()
{
_d2_pri = 4;
_d2_pro = 5;
_d2_pub = 6;
}
void showd()
{
_pub = 1; // 变为子类的protected成员
_pro = 2; // 仍为protected成员
//_pri = 3; // 父类私有成员对子类不可见
}
private:
int _d2_pri;
protected:
int _d2_pro;
public:
int _d2_pub;
};
void TestProtected()
{
Base b;
b._pub = 1;
//b._pro = 2; // 父类对象不可访问父类保护成员
//b._pri = 3; // 父类对象不可访问父类私有成员
Derived2 d2;
//d2._pub = 1; // 父类的public成员权限被修改为protected,子类对象不可访问
//d2._pro = 2; //子类对象不可访问父类保护成员
//d2._pri = 3; // 子类对象不可访问父类私有成员
d2._d2_pub = 4;
}
(3)私有继承
// private私有继承
class Derived3 :private Base
{
public:
Derived3()
{
_d3_pri = 4;
_d3_pro = 5;
_d3_pub = 6;
}
void showd()
{
_pub = 1; // 变为子类的privite成员
_pro = 2; // 变为子类的privite成员
//_pri = 3; // 父类私有成员对子类不可见
}
private:
int _d3_pri;
protected:
int _d3_pro;
public:
int _d3_pub;
};
void TestPrivate()
{
Base b;
b._pub = 1;
//b._pro = 2; // 父类对象不可访问父类保护成员
//b._pri = 3; // 父类对象不可访问父类私有成员
Derived3 d3;
//d3._pub = 1; // 父类的public成员权限被修改为private,子类对象不可访问
//d3._pro = 2; // 父类的protected成员权限被修改为private,子类对象不可访问
//d3._pri = 3; // 子类对象不可访问父类私有成员
d3._d3_pub = 4;
}
总结一下继承方式
1 基类的private成员在派生类中是不能被访问的,如果基类成员不想在类外直接被访问,但需要在派生类中能访问,就定义为protected。可以看出保护成员限定符是因继承才出现的。
2不管是哪种继承方式,在派生类内部都可以访问基类的公有成员和保护成员,基类的私有成员存在但是在子类中不可见(不能访问)。
3 使用关键字class时默认的继承方式是private,使用struct时默认的继承方式是public,不过最好显示的写出继承方式。
二 派生类(子类)的默认成员函数
1 继承关系中构造函数和析构函数
(1)继承关系中的构造函数和析构函数的调用
构造函数的调用顺序 :Derived d;
析构函数的调用顺序 :
说明:
a 、基类没有缺省构造函数,派生类必须要在初始化列表中显式给出基类名和参数列表。
b、基类没有定义构造函数,则派生类也可以不用定义,全部使用缺省构造函数。
c、基类定义了带有形参表构造函数,派生类就一定定义构造函数 (无参或者带参)
代码举例
<span style="font-size:18px;">class A{
public:
A(){cout<<"this is A::A()"<<endl;}
A(int b){cout<<"this is A::A(int b): the value of b is: "<<b<<endl;}
A(double b){cout<<"this is A::A(double b) the value of b is: "<<b<<endl;}
};
class B:public A{
public:
B():A(){} //调用基类 A 默认构造函数
B(int b):A(b){} //调用基类 A 的 A::A(int b) 构造函数
B(double b):A(b){} //调用基类 A 的 A::A(double b) 构造函数
};
void main()
{
B b0,b1(5),b2(10.5);//产生三个实例,分别调用不同的基类构造函数
system("pause");
}
/***********************************
调用 func 函数的输出结果:
this is A::A()
this is A::A(int b): the value of b is: 5
this is A::A(double b) the value of b is: 10.5
***********************************/</span>
2继承体系中的作用域
2.a. 在继承体系中基类和派生类是两个不同作用域。
2.b. 子类和父类中有同名成员,子类成员将屏蔽父类对成员的直接访问。(在子类成员函数中,可以使用 基类::基 类 成员 访问)--隐藏 --重定义
2.c. 注意在实际中在继承体系里面最好不要定义同名的成员。
2.c. 注意在实际中在继承体系里面最好不要定义同名的成员。
3继承与转换--赋值兼容规则--public继承
记忆法: 大的可以赋值给小的
注意:只有public继承才有
3.a. 子类对象可以赋值给父类对象(切割/切片)
3.b. 父类对象不能赋值给子类对象
3.c. 父类的指针/引用可以指向子类对象
3.d. 子类的指针/引用不能指向父类对象(可以通过强制类型转换完成)
3.b. 父类对象不能赋值给子类对象
3.c. 父类的指针/引用可以指向子类对象
3.d. 子类的指针/引用不能指向父类对象(可以通过强制类型转换完成)
4 友元与继承
友元关系不能继承,也就是说基类友元不能访问子类私有和保护成员
注意下面的例子:<<运算符的重载函数 不能说明友元关系可以继承
<span style="font-size:18px;">class Base
{
public:
friend ostream& operator<<(ostream& _cout,Base &base)
{
_cout << base._pri << endl;
return _cout;
}
private:
int _pri;
};
class Derived :public Base
{
};
void TestBase()
{
Base b;
cout << b;
Derived d;
cout << d; // 参数发生类型转换 派生类对象赋值给基类对象
}</span>
三 继承方式 单继承 多继承( 菱形继承)
单继承
class A
{
public:
A()
{
_a = 1;
}
public:
int _a;
};
class B: public A
{
public:
B()
{
_b = 2;
}
public:
int _b;
};
// 创建一个B 类的对象b 查看内存 0x004FFAD8 00000001 00000002
单继承的数据模型
多继承(普通)
class A
{
public:
A(int a)
:_a(a)
{
}
public:
int _a;
};
class B
{
public:
B(int b)
:_b(b)
{
}
public:
int _b;<strong>
</strong>};
class C:public A,public B
{
public:
C(int a,int b,int c)
: B(a) // 不是按初始化顺序来初始化派生类的
, A(b) // 而是按继承顺序 public A public B 来调用其构造函数
, _c(c)
{
}
public:
int _c;
};
//创建一个C 类的对象c 查看内存 0x0023F904 00000002 00000001 00000003
数据模型:
多继承中的菱形继承(也叫钻石继承)
class A
{
public:
A(int a = 0)
{
}
public:
int _a;
};
class B1:public A
{
public:
B1(int b)
:_b1(b)
{
}
public:
int _b1;
};
class B2 :public A
{
public:
B2(int b2)
:_b2(b2)
{
}
public:
int _b2;
};
class C :public B1,public B2
{
public:
C(int b1,int b2,int c)
: B1(b1)
, B2(b2)
, _c(c)
{
}
public:
int _c;
};
void testD()
{
C c(1,2,3);
c.B1::_a = 4; // 必须指定_a的作用域 不然不知道_a属于B1 还是B2
c.B2::_a = 5; // 因此这样就存在二义性
}
数据模型
由于存在二义性 因此引入虚继承
虚继承:
class A
{
public:
A(int a = 0)
{
_a = a;
}
public:
int _a;
};
class B1:virtual public A
{
public:
B1(int b)
:_b1(b)
{
}
public:
int _b1;
};
class B2 :virtual public A
{
public:
B2(int b2)
:_b2(b2)
{
}
public:
int _b2;
};
class C :public B1,public B2
{
public:
C(int b1,int b2,int c)
: B1(b1)
, B2(b2)
, _c(c)
{
}
public:
int _c;
};
void testD()
{
cout << sizeof(C) << endl; // 24 B1的大小(8)+B2的大小(8)+C的成员变量(4) =20 多了4个字节
C c(1,2,3);
//c._a = 1; // 这样就不用作用域限定来指定_a所属
}
数据模型:
关于 继承这块 就给大家分享这么多了,欢迎大家指错