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

C++ 实验二 继承和多态

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

C++ 实验二 继承和多态

目录

一、继承

1.继承访问权限测试

2.友元类继承测试

3.总结

二、多态

1.多态性

 2.一般多态性函数

3.特殊多态性函数

4.析构函数的多态性

5.多继承

6.总结


一、继承

1.继承访问权限测试

类A:

class A{
public:
    int _a=1;
protected:
    int _b=2;
private:
    int _c=3;
};

类B1以public方式继承A:

class B1:public A{
public:
    void Test(){
        _a=10;
        _b=10;
        //_c=10;//'_c' is a private member of 'A'
    }
    int B1_pub_b1=11;
protected:
    int B1_pro_b2=12;
private:
    int B1_pri_b3=13;
};

类B2以protected方式继承B:

class B2:protected A{
public:
    void Test(){
        _a=10;
        _b=10;
        //_c=10;//'_c' is a private member of 'A'
    }
    int B2_pub_b1=21;
protected:
    int B2_pro_b2=22;
private:
    int B2_pri_b3=23;
};

类B3以private方式继承A:

class B3:private A{
public:
    void Test(){
        _a=10;
        _b=10;
        //_c=10;//'_c' is a private member of 'A'
    }
    int B3_pub_b1=31;
protected:
    int B3_pro_b2=32;
private:
    int B3_pri_b3=33;
};

类newB3以private方式继承A,并把A中的部分public成员提升为public:

class newB3:private A{
public:
    void Test(){
        _a=10;
        _b=10;
        //_c=10;//'_c' is a private member of 'A'
    }
    int B3_pub_b1=31;
    using A::_a;//用{using A::_a; }把A中的部分public成员提升为public
protected:
    int B3_pro_b2=32;
private:
    int B3_pri_b3=33;
};

测试结果:

int main(){
    A a;
    B1 t1;
    B2 t2;
    B3 t3;
    newB3 t4;
    cout<<"A: ";
    cout<

2.友元类继承测试

类A:

class A{
private:
    int a;
    friend class C;
};

类B:

class B: public A{
private:
    int b;
};

类C:

class C{
public:
    void Test(){
        B b1;
        b1.a;
        //b1.b;//b is private member of B
    }
};

类D:

class D:public C{
public:
    void Test(){
        A a1;
        //a1.a;//a is a private member of A
        B b2;
        //b2.a;//a is a private member of A
        //b2.b;//b is private member of B
    }
};

3.总结

public继承的访问控制:

1、基类的public和protected成员:访问属性在派生类中保持不变;

2、基类的private成员:不可直接访问。

访问权限:

1、派生类的成员函数,可以直接访问基类中的public和protected成员,但不能直接访问基类的private成员;

2、通过派生类的对象,只能访问public成员。

private继承的访问控制:

1、基类的public和protected成员,都以private身份出现在派生类中;

2、基类的private成员:不可直接访问。

访问权限:

1、派生类的成员函数,可以直接访问基类中的public和protected成员,但不能直接访问基类的private成员;(调用基类的函数时,可用base::test().)

2、通过派生类的对象,不能访问从基类继承的任何成员。

protected继承的访问控制:

1、基类的public和protected成员:都以protected身份出现在派生类中;

2、基类的private成员:不可直接访问。

访问权限:

1、派生类的成员函数,可以直接访问基类中的public和protected成员,但不能直接访问基类的private成员;

2、通过派生类的对象,不能访问从基类继承的任何成员。


        通常,类的私有成员只能由本类的成员访问,外部函数只能访问类的成员函数,再由成员函数访问类的私有成员。但是,如果在某个类定义中用friend声明了一个外部函数(也许是其他类的一个成员)后,这个外部函数便可以例外地访问该类的任何私有成员。用friend声明了的外部函数称为这个类的友元函数。友元关系是单向的,不具有交换性。友元关系也不具有传递性。友元关系不能被继承,基类的友元类未必是子类的友元,某类型的友元的子类未必是该类型的友元。

二、多态

1.多态性

        在面向对象方法中,所谓多态性就是不同对象收到相同消息,产生不同的行为。在C++程序设计中,多态性是指用一个名字定义不同的函数,这些函数执行不同但又类似的操作,这样就可以用同一个函数名调用不同内容的函数。换言之,可以用同样的接口访问功能不同的函数,从而实现“一个接口,多种方法”。     

        在C++中,多态性的实现和联编(也称绑定)这一概念有关。一个源程序经过编译、链接,成为可执行文件的过程是把可执行代码联编(或称装配)在一起的过程。其中在运行之前就完成的联编成为静态联编(前期联编);而在程序运行之时才完成的联编叫动态联编(后期联编)。

        静态联编支持的多态性称为编译时多态性(静态多态性)。在C++中,编译时多态性是通过函数重载和模板实现的。利用函数重载机制,在调用同名函数时,编译系统会根据实参的具体情况确定索要调用的是哪个函数。

        动态联编所支持的多态性称为运行时多态(动态多态)。在C++中,运行时多态性是通过虚函数来实现的。

 2.一般多态性函数

输入输出参数完全一样,在父类中添加virtual;

#include 
#include 
using namespace std;

class Person
{
public:
	virtual void BuyTicket()
	{
		cout << "买票:全价" << endl;
	}
};
class Student : public Person
{
public:
	void BuyTicket(){
		cout << "买票:半价" << endl;
	}
};
class Old:public Person
{
public:
	void BuyTicket()	{
		cout<<"买票:半价"<BuyTicket();
	}
	system("pause");
	return 0;
}

        在派生类中重写的成员函数可以不加virtual关键字,也是构成重写,因为继承后基类的虚函数被继承下来,在派生类中依旧保持虚函数的属性,我们只是重写了它。这是非常不规范的,在平时尽量不要这样使用。

        若子类中的函数有virtual修饰,而父类中没有,则会构成函数隐藏。基类中的析构函数如果是虚函数,那么派生类的析构函数就重写了基类的析构函数。这里他们的函数名不相同,看起来违背了重写的规则,其实不然,这里可以理解为编译器对析构函数的名称做了特殊处理,编译后析构函数的名称统一处理成destructor,这也说明基类的析构函数最好写成虚函数。

3.特殊多态性函数

输入或输出参数在子类中是父类的指针或基类的引用,在子类中对于的是子类的指针或子类的引用。

void getBuy(Person* P){
	P->BuyTicket();
}
int main()
{
	Person per;
	Student stu;
	Old old;
	getBuy(&per);
	getBuy(&stu);
	getBuy(&old);
	return 0;
}

4.析构函数的多态性

        在应用C++的多态特性时,常常会碰到一种情况,就是当指向基类的指针被释放时,派生类的析构函数其实没有被调用,导致在派生类中申请的空间没有被释放,导致内存泄漏。

#include 
using namespace std;
 
class Mammal {
public:
    Mammal() {cout << "Mammal constructor... n";}
    // virtual ~Mammal() {cout << "Mammal destructor... n";}
    ~Mammal() {cout << "Mammal destructor... n";}
    virtual void Speak() const {cout << "Mammal speak!n";}
};
 
class Dog:public Mammal {
public:
    Dog() {
        p = new int(0);
        cout << "Dog Constructor...n";
    }
    ~Dog() {
        cout << "Dog destructor...n";
        delete p;
    }
    void Speak() const {cout << "Woof!n";}
private:
    int *p;
};
 
int main() {
    Mammal* pDog = new Dog;
    pDog->Speak();
    delete pDog;
    return 0;
}

派生类Dog的析构函数没有调用,Dog的构造函数申请的空间泄漏了。此时,虚析构函数能够有效的防止这种情况的出现。 

class Mammal {
public:
    Mammal() {cout << "Mammal constructor... n";}
    virtual ~Mammal() {cout << "Mammal destructor... n";}
    // ~Mammal() {cout << "Mammal destructor... n";}
    virtual void Speak() const {cout << "Mammal speak!n";}
};

        通过将基类的析构函数声明为虚析构函数,成功的通过基类指针调用了派生类的析构函数,完成了内存的释放。 

5.多继承

多继承的概念: 如果一个派生类从多个基类继承, 则称为多继承。

多继承的声明:
class 派生类名:访问控制 基类名1, 访问控制 基类名2, …
{
成员列表
}

虚继承:

#include
using namespace std;
class base
{
public:
	int base;
	virtual void say() {
		cout << "I am base" << endl;
	}
};
class A : public base
{
public:
	int a;
};
class B : public base
{
public:
	int b;
};
class C :public A, public B
{
public:
	int c;
};
int main()
{
	C c;
	c.say();
	return 0;
}

此时出现二义性,可以使用虚继承

class A : virtual public base
{
public:
	int a;
};
class B : virtual public base
{
public:
	int b;
};

6.总结

虚函数的定义要遵循以下重要规则: 

  1. 如果虚函数在基类与派生类中出现,仅仅是名字相同,而形式参数不同,或者是返回类型不同,那么即使加上了virtual关键字,也是不会进行滞后联编的。 
  2. 只有类的成员函数才能说明为虚函数,因为虚函数仅适合用与有继承关系的类对象,所以普通函数不能说明为虚函数。 
  3. 静态成员函数不能是虚函数,因为静态成员函数的特点是不受限制于某个对象。 
  4. 内联(inline)函数不能是虚函数,因为内联函数不能在运行中动态确定位置。即使虚函数在类的内部定义定义,但是在编译的时候系统仍然将它看做是非内联的。 
  5. 构造函数不能是虚函数,因为构造的时候,对象还是一片位定型的空间,只有构造完成后,对象才是具体类的实例。 
  6. 析构函数可以是虚函数,而且通常声名为虚函数。 

        多态的特性的virtual修饰,不单单对基类和派生类的普通成员 函数有必要,而且对于基类和派生类的析构函数同样重要。

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

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

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