0
点赞
收藏
分享

微信扫一扫

C++_继承、二义性、虚继承

继承
子类拥有父类所有的成员变量和函数、子类是一种特殊的父类、
子类可以当做父类的对象使用、子类可以拥有父类没有的方法和属性。

class parent{
public:
int a;
int b;
public:
void print(){
a=0;
b=0;
cout<<a<<b<<endl;
}
};
class child::public parent{
private:
int c;
};
int main(){
child c;
c.a=1;
c.b=2;
c.print();
}

继承的访问控制

C++中的继承方式会影响子类对外访问属性
1 看调用语句,是在类的外部还是在类的内部
2 看子类如何从父类中继承
3 看父类中的访问级别

public:父类在子类中保持原有的访问级别
private:父类在子类中变为private
protected:父类中的public变为protected;父类中的protected还是protected;
父类中private还是private

private成员在子类中依然存在,但是却无法访问,不论何种方式继承基类,
派生类都不能直接使用基类的私有成员

public继承


class parent{
public:
int a;
protected:
int b;
private:
int c;
};
class child:public parent{
public:
void use_var(){
a=0; ok
b=0; ok
c=0; err
}
};
int main(){
child c;
c.a=0; ok
c.b=0; err
c.c=0; err
}
private继承


class parent{
public:
int a;
protected:
int b;
private:
int c;
};
class child:private parent{
public:
void use_var(){
a=0; ok
b=0; ok
c=0; err
}
};
int main(){
child c;
c.a=a; err
c.b=b; err
c.c=c; err
}
protected继承


class parent{
public:
int a;
protected:
int b;
private:
int c;
};
class child: protexted parent{
public:
void use_var(){
a=0; ok
b=0; ok
c=0; err
}
};
int main(){
child c;
c.a=a; err
c.b=b; err
c.c=c; err
}

继承中的类型兼容性原则
子类对象可以当做父类对象使用,子类对象可以直接赋值给父类对象
子类对象可以直接初始化父类对象
父类指针可以直接指向子类对象,父类引用可以直接引用子类对象

class parent{
public:
void print_p(){
cout<<"parent"<<endl;
}
private:
int a;
};
class child:public parent{
void print_c(){
cout<<"child"<<endl;
}
private:
int b;
};
void print_p(parent *p){
p->print_p();
}
void print_p2(parent &p){
p.print_p();
}
int main(){
parent p;
p.print_p();

child c1, c2;
c1.print_p();
c2.print_p();

类型兼容性原则

基类指针可以指向派生类对象
parent *p2=&c1;
p2->print_p();

指针做函数参数
print_p(&p2);
print_p(&c1);

引用做函数参数
print_p(p2);
print_p(c1);

子类对象初始化父类对象
parent p3=c1;
}

继承中的构造和析构
在子类对象构造时,需要调用父类构造函数对其继承得来的成员进行初始化
在子类对象析构时,需要调用父类析构函数对其继承得来的成员进行析构

#include <iostream>
using namespace std;

class parent{
public:
parent(int a, int b){
this->a=a;
this->b=b;
cout<<"父类构造函数"<<endl;
}
void print_p(){
cout<<"父类"<<endl;
}
~parent(){
cout<<"父类析构函数"<<endl;
}
private:
int a;
int b;
};
class child:public parent{
public:
child(int a, int b, int c):parent(a, b){
this->c=c;
cout<<"子类构造函数"<<endl;
}
void print_c(){
cout<<"子类"<<endl;
}
~child(){
cout<<"子类析构函数"<<endl;
}
private:
int c;
};
int main(){
parent(1, 2);
child(1, 2, 3);

构造函数调用顺序:先调用父类的构造函数,在调用子类的构造函数
析构函数调用顺序:和构造顺序相反
}

继承中同名成员变量处理方法
1 当子类成员变量与父类成员变量相同时,子类依然继承父类的同名成员
2 在子类中通过域分辨符::进行同名成员的区分(在派生类中使用基类的同名成员,显示的使用类名限定符)
3 同名函数存储在内存的不同位置
注意:在子类中使用成员默认为自己类中的成员

class A{
public:
int a;
int b;
public:
void print(){
cout<<a<<b<<endl;
}
};
class B:public A{
public:
int a;
int b;
public:
void print(){
cout<<a<<b<<endl;
}
};
int main(){
B b;
b.a=1; 修改B中的a
b.A::a=1; 修改A中的a
b.print(); 调用B中的函数
b.a::print(); 调用A中的函数
}

派生类中的static关键字
基类中定义的静态成员,将被所有派生类共享
遵循派生类的访问控制
派生类中访问静态成员,用以下形式显示说明
类名::成员 或通过对象访问:对象名.成员

多继承(一个类有多个直接基类的继承关系)的应用
语法: class 派生类名:访问控制 基类名1,访问控制 基类名2

class base1{
public:
int a;
};
class base2{
public:
int b;
};
class child: public base1, public base2{
public:
int c;
public:
child(int a, int b, int c):base1(a), base2(b){
this->c=c;
}
};

二义性与虚继承
如果一个派生类从多个基类派生,而这些基类又有一个共同的积累,
则在对该类中声明的名字进行访问时,可能产生二义性

class A{
public:
int a;
};
class B1: public A{
public:
int b1;
};
class B2: public A{
public:
int b2;
};
class C: public B1, public B2{
int c;
};
int main(){
C c;
c.c=1; ok
c.b1=1; ok
c.b2=1; ok
c.a=1; err
}

虚继承解决方案

class A{
public:
int a;
};
class B1: virtual public A{
public:
int b1;
};
class B2: virtual public A{
public:
int b2;
};
class C: public B1, public B2{
int c;
};
int main(){
C c;
c.c=1; ok
c.b1=1; ok
c.b2=1; ok
c.a=1; ok
}

如果不加virtual关键字,会执行两次A的构造函数
虚继承只能解决有共同基类的成员

virtual关键字会在类中添加属性,从而会使由该类声明的对象所占的内存空间增大


举报

相关推荐

0 条评论