C++语言入门(七) 继承

一.原则:

父类/子类
基类/派生类

二.语法:

class 派生类 : [访问限定符] 基类 {
  成员
}

例:(成员函数)

#include<iostream>
using namespace std;

class Father{
public:
	Father(){
		cout << __func__ << endl;
	}
	~Father(){
		cout << __func__ << endl;
	}
	void FatherTest(){
		cout << __func__ << endl;
	}
};

class Son:public Father{
public:
	Son(){
		cout << __func__ << endl;
    }
	~Son(){
		cout << __func__ << endl;
	}
};

int main(){
	Son s;
	s.FatherTest();
}

输出:

Father
Son
FatherTest
~Son
~Father

先调用Father的构造函数,先调用son的析构函数

注:

当父类中只有带参构造函数和成员变量(公有),子类只有默认构造函数,则不可编译。

1.但可以使子类的构造函数中调用父类的带参构造函数

Son():Father(10){ } 

2.也可以子类构造函数含参数传到父类中,让父类去构造

Son(int n):Father(n) 

构造子类对象时:Son s(100); 

3.可以继承的基础上再继承 ,例:三角形

#include<iostream>
#include<cmath>
using namespace std;

class Triangle{
	int a,b,c;
public:
	Triangle(int a,int b,int c):a(a),b(b),c(c){}//构造
	int GetLength()const{
		return a+b+c;
	} 
	float GetArea()const{
		float h = GetLength()/2.0;
		return sqrt(h*(h-a)*(h-b)*(h-c));
	}
};

class IsoscelesTriangle:public Triangle{//等腰三角形 (继承三角形) 
public:
	IsoscelesTriangle(int bottom,int side):Triangle(bottom,side,side){}
};

class EquilteralTriangle:public IsoscelesTriangle{//等边三角形(继承等腰三角形) 
public:
	EquilteralTriangle(int side):IsoscelesTriangle(side,side){}
};

int main(){
	Triangle t(3,4,5);
	cout << t.GetLength() << endl;
	cout << t.GetArea() << endl;
	
	EquilteralTriangle et(3);
	cout << et.GetLength() << endl;
	cout << et.GetArea() << endl;
	
	IsoscelesTriangle it(4,7);
	cout << it.GetLength() << endl;
	cout << it.GetArea() << endl;
}

三.protected

作用:让派生类能够访问公众不能使用的内部函数 

       子类内部访问父类成员,只能访问publicprotected成员。

也继承了private成员,但是不能访问。

继承方式: 

  • public无论类内部还是类对象都可以访问。
  • protected类对象不可访问,类内部与继承类的内部可以访问。
  • private只有类内部可以访问。
  • 简看:

 四.同名隐藏规则(平时最好不要重名)

成员变量同名,会隐藏基类。 

#include<iostream>
using namespace std;

class Base{
public:
	int n;
	void PrintBase(){
		cout << &n << ":" << n << endl;
	}
}; 

class Derive:public Base{
public:
	int n;
	void PrintDerive(){
		cout << &n << ":" << n << endl;
	}
};

int main(){
	Derive d;
	d.n = 100;
	d.PrintBase() ;
	d.PrintDerive() ;
}

 输出为:0x6ffe10:0
                0x6ffe14:100

要想避免这种情况,可以专门给基类赋值 

d.Base::n = 10; 

成员函数同名 ,大体与成员变量情况相同。

注:假如父类中有同名重载函数(函数名相同,参数不相同),子类中没有。当直接调用该函数时会出错,因为一旦在子类中找到重名函数,就不会再去父类中找重载函数,只有当子类中没有重名函数,才会再去父类中找函数。解决方法:

①在子类中写:using Base::Test;

②在main中写:d.Base::Test(20); 

五.赋值兼容原则 

概念:在任何需要基类(父类)对象的地方都可以使用公有的派生类(子类)对象来代替。反之,不可。 

1.子类的对象可以直接赋值给父类的对象。

Base base;
Derive derive;
base = derive;

2.子类的对象可以初始化父类的引用。

Derive derive;
Base& base = derive;

 3.子类对象的地址可以赋给指向父类的指针,指向父类对象的指针变量也可以指向子类对象。

Derive derive;
Base* base = &derive;

 注:还可以用此来解决同名隐藏

Base& f = d;//d是子类对象
f.Test(); //此时调用的是父类的
//or:
Base* p = d;
p->Test();

六.补充:

当子类和父类有拷贝构造函数赋值运算符重载函数时,在子类中需要负责父类的拷贝和赋值

(最好使用默认的)

Derice(const Derice& d):Base(d){
	n = d.n;
}
Derice& operator=(const Derice&){
	n = d.n;
	Base& b = *this;
	b = d; //赋值兼容
	return* this; 
}

 七.多重继承(java不允许)

class 类名 : public 基类1,public 基类2{
};
#include<iostream>
using namespace std;

class Base1{
	int n;
public:
	Base1(int n):n(n){}
	void PrintN(){
		cout <<__func__<< "(" << n << ")" << endl;
	} 
};
class Base2{
	int m;
public:
	Base2(int m):m(m){}
	void PrintM(){
		cout <<__func__<< "(" << m << ")" << endl;
	} 
};

class Derive:public Base1,public Base2{
public:
	Derive(int n,int m):Base1(n),Base2(m){
		
	}
};

int main(){
	Derive d(1,2);
	d.PrintN() ;
	d.PrintM() ;
}

输出:PrintN(1)
PrintM(2)

1.两个父类中不允许出现重名函数 

2.钻石继承/菱形继承

例:B,C继承了A,D继承了B,C。下列代码会出现什么情况?

#include <iostream>
using std::cout;
using std::endl;
class A{
public:
      void test();
private:
      int id;
};
void A::test(){
    cout << __func__ << endl;
}
class B : public A {};
class C : public A {};
class D : public B,public C{};
int main(){
    cout << "A size:" << sizeof(A) << endl;
    cout << "B size:" << sizeof(B) << endl;
    cout << "C size:" << sizeof(C) << endl;
    cout << "D size:" << sizeof(D) << endl;
    D d;
    d.test();
}

 会报错,不确定test()调用的是B的还是C的,应在前加上访问限定符,d.B::test()

  • 虚继承 

为了节省空间,可以将B、C对A的继承定义为虚拟继承,而A就成了虚拟基类 

class A; 
class B:vitual public A; 
class C:vitual public A; 
class D:public B,public C; 

 子类构造时初始化虚基类(假如有成员时)

Derice(int n,int m):n(n),Base1(m),Base2(m),Base(m){}

 此时就可以调用重名函数,不用加访问限定符

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值