栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > C/C++/C#

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

C/C++/C# 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

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

一.原则:

父类/子类
基类/派生类

二.语法:

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

例:(成员函数)

#include
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
#include
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

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

       子类内部访问父类成员,只能访问public和protected成员。

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

继承方式: 

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

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

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

#include
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
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 
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){}

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

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/690930.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号