C++继承与派生

类的继承和派生允许我们在保持原有类的基础上,进行修改和扩充。

原有的类称为基类或父类,新类称为派生类或子类。


关于类成员的权限

类成员可以分为:不可访问成员、保护成员、私有成员、公有成员。

不可访问成员:从基类私有成员继承而来的,派生类无法直接访问。

保护成员:类内部可以直接访问。外部不可直接访问。其子类可以访问。

私有成员:类内部可以直接访问。外部不可直接访问。其子类不可以访问。

公有成员:大家都可以访问。

#include<iostream>
using namespace std;
class A
{
public:    //公有成员
    int p1;       //公有成员类内外都可以访问
    void p(){       //类内访问
        p1=1;
        p2=2;
        p3=3;
    }
private:   //私有成员
    int p2;      //私有成员只有类内可以访问
    void pp(){    //类内访问
        p1=11;
        p2=22;
        p3=33;
    }  
protected:    //保护成员
    int p3;     //保护成员只有类内可以访问
    void ppp(){    //类内访问
        p1=111;
        p2=222;
        p3=333;
    }
};  
int main()
{ 
    A a1;
    a1.p1=1;    //类外访问
    return 0;
} 



继承方式

公有继承:基类的公有成员和保护成员在派生类里属性不变,基类的私有成员在派生类里变成不可访问成员。

私有继承:基类的公有成员和保护成员在派生类里变成私有成员,基类的私有成员在派生类里变成不可访问成员。

保护继承:基类的公有成员在派生类里变成保护成员,基类的私有成员在派生类里属性不变,基类的私有成员在派生类里变成不可访问成员。


#include<iostream>
using namespace std;

class A         //在A类内p1为公有成员,p2为私有成员,p3为保护成员
{
public:
    int p1;
    void show_p(){
        p1=1;
        p2=2;
        p3=3;
        cout<<"p1="<<p1<<" p2="<<p2<<" p3="<<p3<<endl;
    }
private:
    int p2;
protected:
    int p3;
};

class B:public A     //B公有继承了A,p1在B类内为公有成员,p2为不可访问成员,p3为保护成员
{
public:
    void show_b(){
        p1=11;
        p3=33;
        cout<<"p1="<<p1<<" p3="<<p3<<endl;
    } 
};

class C:private A    //C私有继承了A,p1在C类内为私有成员,p2为不可访问成员,p3为私有成员
{
public:
    void show_c(){
        p1=111;
        p3=333;
        cout<<"p1="<<p1<<" p3="<<p3<<endl;
    }
};

class D:protected A  //D保护继承了A,p1在D类内为保护成员,p2为不可访问成员,p3为保护成员
{
public:
    void show_d(){
       p1=1111;
       p3=3333;
       cout<<"p1="<<p1<<" p3="<<p3<<endl;
    }
};

int main()
{
    A a1;
    B b1;
    C c1;
    D d1;
    b1.show_b();
    c1.show_c();
    d1.show_d();
    
    return 0;
}  

当派生类继承多个基类时,利用作用域分辨符避免二义性

#include<iostream>
class A{
public:
    int a;
};


class B{
public:
    int a;
};


class C:public A,public B{    //C类内有a具有二义性
public:
    int c;
};
  
int main()
{
    C c1:a=2;
    c1.A::a=1;     //利用::来确定访问的是哪个
    c1.B::a=2;
    std::cout<<c1.A::a<<" "<<c1.B::a<<std::endl;
    return 0;
 }   


当派生类多次继承同种基类时,可以利用虚基类使其通用,在内存中只占一个副本


#include<iostream>
using namespace std;
class A{
public:
    int a;
};

class B1:virtual public A{    //将A设为虚基类
public:
    void show(){
        cout<<"B1.a="<<a<<endl;
    }
};

class B2:virtual public A{     //将A设为虚基类
public:
    void show(){
        cout<<"B2.a="<<a<<endl;
    }
};

class C:public B1,public B2{    //C类里有共同基类A
};

int main()
{
    C c;
    c.a=1;
    c.B1::show();
    c.B2::show();
}

结果

B1.a=1
B2.a=1


虚基类的构造函数及析构函数
当共同基类有构造函数时,其如果是虚基类,则只运行一次构造函数;析构函数同理


#include<iostream>
using namespace std;

class A0{      //共同基类
public:
    A0(){        //构造函数
        a=1;
        cout<<"init A0.a="<<a<<endl;
    }
    int a;
    ~A0(){       //析构函数
        cout<<"A0.a="<<a<<endl;
    }
};

class A1: virtual public A0{    //A0为虚基类
public:
    A1(){
        a=2;
        cout<<"init A1.a="<<a<<endl;
    }
    ~A1(){
        cout<<"A1.a="<<a<<endl;
    }
};

class A2: virtual public A0{   //A0为虚基类
public:
   A2(){
       a=3;
       cout<<"init A2.A="<<a<<endl;
   }
   ~A2(){
       cout<<"A2.A="<<a<<endl;
   }
};

class Derived: public A1,public A2{
public:
    Derived(){
        a=5;
        cout<<"init Derived.a="<<a<<endl;
    }
    ~Derived(){
        cout<<"Derived.a="<<a<<endl;
    }
};

int main()
{
    Derived d;
    return 0;
}

结果:

init A0.a=1
init A1.a=2
init A2.A=3
init Derived.a=5
Derived.a=5
A2.A=5
A1.a=5
A0.a=5



隔代继承访问,小心产生歧义基类

#include<iostream>
using namespace std;
class A{
public:
    int a;
};

class A1{
public:
    int a;
};

class B:public A,public A1{   
};

class B1:public A,public A1{
     
};

class C:public B, public B1{   //C类内包含四个int a
};


int main()
{
    C c;
    c.B::A::a=2; 
    return  0;
}

隔代继承访问比较坑的一点是你的编译器可能会报错

错误:‘A’ 是 ‘C’ 的有歧义的基类

这时候换个编译器试试,我用VS2010可以编译成功


当子类和父类的函数发生重命时,会发生隐藏

如果子类函数与父类函数同名,不管参数是否相同,父类函数都将被隐藏。

#include<iostream>
using namespace std;

class A{
public:
	int a;
	A(){
	    a=1;
	}
	void show(){            //父类函数
		cout<<"A.a="<<a<<endl;
	}
};

class B:public A{
public:
	int b;
	B(){
		b=2;
	}
	void show(){                       //子类函数,与父类函数重名,父类函数被隐藏
		cout<<"B.b="<<b<<endl;
	}
};

int main()
{
	B b;
	B *p;
	p=&b;
	b.show();
}


结果

B.b=2


当基类指针指向派生类对象

1)该指针只能访问派生类对象中的继承该基类的部分

2)当该派生类多次继承该基类时,指针一般默认访问的是血缘关系最近的基类部分。

3)如果有同辈份的二个以上的相同基类,则须通过间接指针来访问

#include<iostream>
using namespace std;

class A{
public:
	int a;

	A(){
		cout<<"begin A"<<endl;
	    a=1;
	}

	void show(){
		cout<<"A.a="<<a<<endl;
	}

	~A(){
		cout<<"over A"<<endl;
	}

};

class C0:public A{
public:
	C0(){
		a=33;
	}
};

class C:public A{
public:
	C(){
		a=22;
	}
};

class B:public C,public A{       //C类当前二次继承了A类
public:
	int b;

	B(){
		cout<<"begin B"<<endl;
		b=2;
	}

	void show1(){
		cout<<"B.b="<<b<<endl;
	}

	~B(){
		cout<<"over b"<<endl;
	}
};

int main()
{
	A *p;
	B b;
	p=&b;        
	p->show();     //这里默认访问的是关系近的A;
        p->B::A::show();     //这里指明要访问关系远点的A;
}



结果

begin A
begin A
begin B
A.a=1
A.a=2
over b
over A
over A



当派生类多次继承的基类关系一样近时

class B:public C,public C0{
public:
	int b;

	B(){
		cout<<"begin B"<<endl;
		b=2;
	}

	void show1(){
		cout<<"B.b="<<b<<endl;
	}

	~B(){
		cout<<"over b"<<endl;
	}
};
如果我们要用基类指针访问该派生类,须通过间接指针
int main()
{
	B b;
	C *p;
	p=&b;
	A *pl=p;
	pl->show();
}

结果

begin A
begin A
begin B
A.a=22
over b
over A
over A















  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值