c++面向对象语言基础(封装、继承、多态)

c++面向对象语言基础


类和对象

:数据类型
对象:数据类型的一个实例

如何创建自己的类:

class student
{
    string name;
    int age;
};

如何使用一个类

student aa;
aa.age=20;      //不规范

公有和私有的概念:

class student
{
public:
    string name;
private:
    int age;
}

public:外部可读写
private:外部无法访问
可以只有public

公有和私有(加强版)

private目的:封装

class student
{
public:
    string name;
    void print_name();  //公有方法
private:
    int age;
    void print_age();   //私有方法
}

void  student::print_name()
{
    cout<<"张三";
}
void student::print_age()
{
    cout<<age;
}
//主函数
student aa;
aa.print_name();
aa.print_age();     //报错,提示函数不存在


只有通过公有方法的外壳调用私有的方法
如把上面的代码修改:

class student
{
public:
    string name;
    void print_name();  //公有方法
private:
    int age;
    void print_age();   //私有方法
}

void  student::print_name()
{
    print_age();
}
void student::print_age()
{
    cout<<age;
}
//主函数
student aa;
aa.print_name();

//此时可以正确打印出年龄;


正规程序定义的写法:

class student
{
public:
    void print_age(); 
    void print_name();  //公有方法
private:
    int age;
    string name;  
}

把数据都放在private中,把方法都放在public中
起到防错机制的效果

成员函数的重载

函数名称一样,靠传入参数的差异进行区分调用

class student
{
    public:
    int age;
    string name;
    bool set(int a);
    bool set(string a);
}
student::set(int a)
{}
student::set(string a)
{}

n

构造函数

上述set为成员普通方法,还存在部分特殊方法。如:构造函数;
student aa创建aa对象,aa没有默认值;
如果存在构造函数,则aa有默认值;
构造函数本质即对象的初始化

//不带参数的构造函数
class student
{
public:
    int age;
    string name;
    student();
};

student::student()
{
    age = 20;
    name = "zhangsan"
}
//主函数中
student aa;     //自动调用构造函数,有默认值
//带参数的构造函数
class student
{
public:
    int age;
    string name;
    student();
    student(int a, string b);       //同名构造函数重载
};

student::student(int a, string b)
{
    age = a;
    name = b;
}

student::student()
{
    age = 20;
    name = "zhangsan"
}

//主函数中
student aa;     //自动调用构造函数,有默认值
student bb(22,"李四");

析构函数(正规C++程序、大型)

使用析构函数销毁内存数据

  • 对象aa被创建之后,数据一直存放在内存中。这块内存什么时候被释放?调用析构函数的时候!
  • 主函数中不能直接运行student aa; delete aa;
  • 只有student *p = new student(20."张三"); delete p;才将自动调用析构函数
  • delete时调用
  • 内存中自动删除

写法和构造函数相似

student::`student()
{

}
//无输入,无返回,可以没有内容,也可以cout<<"delete object";

常成员函数 const

//安全,不能修改数据

class student
{
public:
    int age;
    string name;
    bool set(int i);
    bool read() const;      //常成员函数,表示这个函数只读不写
};

bool student::read() const
{
    cout << name;
    cout << age;
    return true;
}

静态成员 static

静态成员数据据

如student类中需要一个sum来统计所有学生类成员的数量

需要一个变量sum,与student类有关,但与它的任何一个对象都无关

这种描述全局,但是与某个对象属性无关的,叫做静态成员数据

读取静态成员数据的方法叫做 静态成员函数


class student
{
public:
    int age;
    string name;
    student();
    static int sum;     //static表示静态成员数据
    static int count();     //static表示静态成员函数,返回有多少个对象
};

student::student()  //
{
    age = 20;
    name = "zhangsan"
    sum = sum + 1;
}

int student::count()      //静态成员函数的定义,注意不加static
{
    return sum;
}
//只有通过静态成员函数,才能访问静态数据

使用静态成员函数

student aa;
student bb;
aa.count();
bb.count();
student::count();
//上述三种count函数使用方式结果完全一致,只有静态函数可以这样

类的派生与继承

什么是派生:

  • 学生类划分为研究生和本科生
  • 学生是父类/基类/超类,本科生和研究生是子类
  • 所谓派生,是相对父类而言
  • 所谓继承,是相对子类而言

派生本科生的写法:

class undergraduate : public sudtent
{
public:
    string course;      //新增定义,学生类中没有
}

派生研究生的写法:

class postgraduate : public sudtent
{
public:
    string research;      //新增定义,学生类中没有
}

没有写name和age,因为子类自动继承

拥有属于自己的新增定义

子类没有构造函数,如何创建它的对象?name和age是否还有值?

postgraduate bb;
bb.set(25);         //调用了父类的构造方法

类在不同情况下的继承
public,private,protect

在没有继承与派生的情况下,protect和private效果完全一样

研究生类定义 class postgraduate : public sudtent

为什么要加上public?

public表示公有继承,只继承student的公有部分{name,age}

并且,age和name也将继续作为研究生类的public部分

研究生类是无法继承也无法访问student类的私有部分

  • 当把父类student类定义的private替换为protect
    • 对student本身没有变化
    • class postgraduate : public student{}时,不仅public部分,protect部分也会被继承
    • student的protect部分也被继承到了postgraduate的protect部分
  • 继承总结
    • 私有继承:把class postgraduate : public student{}中public换成private
    • 保护继承:把class postgraduate : public student{}中public换成protect
父类student有的子类postgraduate继承到的
公有继承public A;
private B;
public A
公有继承public A;
private B;
public A;
private B;
私有继承public A;
private B;
private A;
保护继承public A;
protect B;
protect A,B;

保密优先级:private > protect > public

子类的构造函数

子类可以与自己的构造函数:
子类没有构造函数,系统会调用弗雷德构造函数
无论子类有没有自己的构造函数,父类的构造函数都要被调用

研究生不带参数构造函数:

class postgraduate : public sudtent
{
public:
    string research;      //新增定义,学生类中没有
    postgraduate();
    postgraduate(int a, string b, string c);
}

postgraduate::postgraduate()        //无参构造
{
    research = "asic design";

}

//主函数

postgraduate bb;

创建子类bb对象时,系统会首先自动运行父类的student构造函数,对age和name进行赋值,随后运行子类postgraduate构造函数,对bb对象进行拓展,增加research内容

子类不能继承父类的构造方法,只能调用!

研究生带参数构造函数:

class postgraduate : public sudtent
{
public:
    string research;      //新增定义,学生类中没有
    postgraduate();
    postgraduate(int a, string b, string c);
}

postgraduate::postgraduate()        //无参构造
{
    research = "asic design";

}

postgraduate::postgraduate(int a, string b, string c):student(a, b)     //带参构造函数的定义
{
    research = c;
}
//主函数

postgraduate bb(25, "李四", "ASIC design");

程序会先调用父类student的构造函数,把25和李四两个值传入父类student带参数的构造函数中

随后把参数c = asic design传给bb自己的research属性,实现对研究生对象的全动态初始化赋值

多态

多态:方法可以不专属于某个类,例如对两个字符串也可以使用加法,而非只有int类

c++中实现上述有三种方法:

  • 重载
  • 隐藏
  • 覆盖(override,又叫重写,这个才是c++的多态)

重载:
重载的两个函数的参数格式必须完全不一样

隐藏和覆盖的同名函数的参数可以完全一样

不依赖于面向对象,依赖于编辑器

隐藏:
在父类和子类中都定义一个study()函数,输入的参数格式可以不同

class student
{
public:
    void study(bool a)  {cout<<"好好学习";}
}
class postgraduate
{
public:
    void study(int b)  {cout<<"芯片设计";}
}
//主函数
postgraduate bb;
student aa;
bb.study(2);        //成功
aa.study(true);     //成功
bb.study(true);     //失败,没有重载study(),不能根据传入参数不同调用不同函数,因为这里的父类study被隐藏了(没有被覆盖)

类指针

类指针与结构体指针大致相同

student *p;
student aa;
p = &aa;
p -> name;          
p -> study();       //  对aa执行成员函数
//更高级的写法
student *p = new student(20,"张三");
delete p; //调用析构函数

将继承加入到类指针中:

student *p1;
postgraduate *p2;
student aa;
postgraduate bb;

p1 = &aa;
p2 = &bb;
p1 = &bb;
p2 = &aa;           //报错

父类指针可以指向子类成员,反之不行

研究生一定是学生,学生不一定是研究生

注意: 虽然使用student指针指向postgraduate对象,但不能调用postgraduate中的属性和方法,父类指针指向子类时,仍然只能使用父类的方法

那么如何解决这个问题呢??

真正的多态与虚函数

分别在student,undergraduate,postgraduate中建立一个study方法

  • 都叫study,内容不一样
  • 在所有子类父类study的声明前面加上关键字virtual,表示这是一个虚函数
class student
{
public:
    virtual void study();
}
void student::study(){cout<<"我是学生";}

class postgraduate
{
public:
    virtual void study();
}
void student::postgraduate(){cout<<"我是研究生";}

class undergraduate
{
    public:
    virtual void study();
}
void student::undergraduate(){cout<<"我是本科生";}

//主函数
postgraduate bb;
student aa;
undergradute cc;
student *p;

p = &aa;
p -> study();   //调用学生类的study
p = &bb;
p -> study();   //调用研究生类的study
p = &cc;
p -> study();   //调用本科生类的study

注意:他们的输入参数都是没有参数,这里与重载就不一样了!!因此调用哪一个根据指向的类动态调用

重载时编译时决定的,多态是运行时决定的

纯虚函数与抽象类

抽象类:如果把大学生划分为本科生和研究生,那么一个学生要么属于本科生,要么属于研究生,不能单独属于学生这一类,那么学生就是抽象类

设置抽象类依赖于纯虚函数:

class student
{
public:
    student();
    student(int a, string b);
    virtual void study() =0;    
}
//主函数
student aa;
student *p;
postgraduate bb;
p = &bb;
p -> study();
  • virtual void study() =0; 中声明study方法,注意virtual和=0,意为纯虚函数
  • 此时study()函数只有声明,没有定义,其具体内容靠子类的多态来实现
  • 依然可以创建student类型指针,但不能创建该类型对象
  • 注: 可能存在多个virtual函数,至少要将一个 =0,指明其为纯虚函数
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值