首页 > 编程语言 >c++ OOP(2)

c++ OOP(2)

时间:2023-10-09 15:56:23浏览次数:48  
标签:area int Time c++ Shape 派生类 OOP 基类

目录

运算符重载

重新定义+-*/操作,对同类对象使用,以时间类Time为例子进行理解

Time.h

class Time{
    private:
        int hour, minute;
    public:
        Time();
        Time(int h, int m);
        void show_time();
        Time operator+ (const Time& t);
};

Time.cpp

#include "Time.h"
#include <iostream>
using namespace std;

Time::Time(){
    hour = minute = 0;
}

Time::Time(int h, int m){
    hour = h;
    minute = m;
}

void Time::show_time(){
    cout << hour << "h:" << minute << "min\n";
}

Time Time::operator+(const Time& t){    //使用引用`const Time&`,相比传值,效果相同,效率更高,内存占用更小
    Time sum;
    sum.minute = (this->minute + t.minute) % 60;	//这是成员函数,可以直接访问private成员变量
    sum.hour = this->hour + t.hour + (this->minute + t.minute) / 60;
    return sum;
}

test.cpp

#include <iostream>
#include "Time.h"

int main(){
    Time a = Time(2, 35);
    Time b = Time(2, 40);
    Time c = a + b;		//+号左侧是调用重载运算符的对象,右侧是传参对象
    # Time d = a + b + c;	//也是正确的
    c.show_time();	//output: 5h:15min
    return 0;
}

编译运行

g++ Time.cpp test.cpp

继承

基类,派生类

通常将基类和派生类的声明定义在同一个.h文件中,将基类和派生类的实现定义在同一个.cpp文件中

PS.h

#include <string>
using namespace std;

class Person{
    private:
        string name;
        int age;

    public:
        Person();
        Person(string n, int a);
        void person_info();
};

class Student : public Person{   // `:` 继承语法 派生类:基类
    private:    //派生类继承基类的成员变量,并添加自己的成员变量
        int score;

    public:     //派生类继承基类的成员函数,并添加自己的成员函数
        Student();
        Student(string n, int a, int s);    //构造函数必须给新成员和继承的成员提供数据
        void stu_info();
};

PS.cpp

#include "PS.h"
#include <iostream>
#include <string>
using namespace std;

Person::Person(){}

Person::Person(string n, int a){
    name = n;
    age = a;
}

void Person::person_info(){
    cout << name << "\t" << age << "\t";
}

Student::Student(){}

//注意派生类构造函数的实现  
//通过成员初始化列表将基类信息传递给基类构造函数
Student::Student(string n, int a, int s) : Person(n, a){
    score = s;
}

void Student::stu_info(){
    cout << "\n";
    this->person_info();
    cout << score << "\n";
}

test.cpp

# include <iostream>
#include "PS.h"
using namespace std;

int main(){
    Person p = Person("dctwan", 24);	//基类
    Student s = Student("hhh", 20, 100);	//派生类
    p.person_info();	
    s.person_info();	//派生类调用基类方法
    s.stu_info();		//派生类调用自己的方法
    return 0;
}

编译运行

g++ PS.cpp test.cpp

基类指针指向派生类对象

Student s = Student("hhh", 20, 100);
Person *r = &s;     //基类指针指向派生类对象,反之不行
r->person_info();   //基类指针只能调用基类方法

//r->stu_info();	错误使用

多态

同一个方法在基类和派生类中的行为是不同的,换句话说:根据调用函数的对象的类型来执行不同的函数。有两种方法实现多态

  1. 在派生类中重新定义基类方法
  2. 使用虚方法

方法一:在派生类中重新定义基类方法

此方法会根据指针类型来选择方法,以求矩形和三角形面积为例

Shape.h

class Shape{
    protected:
        int height, weight;
    public:
        Shape(int h, int w);
        double area();
};

class Rectangle: public Shape{
    public:
        Rectangle(int h, int w);
        double area();
};

class Trangle: public Shape{
    public:
        Trangle(int h, int w);
        double area();
};

Shape.cpp

#include <iostream>
#include "Shape.h"
using namespace std;

Shape::Shape(int h, int w){
    height = h;
    weight = w;
}

double Shape::area(){
    cout << "Base Class Area" << "\n";
}

Rectangle::Rectangle(int h, int w) : Shape(h, w){}

double Rectangle::area(){
    return height * weight;
}

Trangle::Trangle(int h, int w) : Shape(h, w){}

double Trangle::area(){
    return 0.5 * height * weight;
}

test.cpp

#include <iostream>
#include "Shape.h"
using namespace std;

int main(){
    Rectangle r = Rectangle(2, 3);
    Trangle t = Trangle(2, 3);
    Shape *shape_r = new Rectangle(2, 3);
    Shape *shape_t = new Trangle(2, 3);
    //使用基类指针,调用的是基类的方法
    cout << "shape_r->Rectangle(2,3) area: " << shape_r->area() << "\t shape_t->Trangle(2,3) area: " << shape_t->area() <<"\n";
    //调用相应派生类的方法 
    cout << "Rectangle(2,3) area: " << r.area() << "\t Trangle(2,3) area: " << t.area() << "\n";
    return 0;
}

编译运行

g++ Shape.h Shape.cpp test.cpp

结果如下

shape_r->Rectangle(2,3) area: Base Class Area0   shape_t->Trangle(2,3) area: Base Class Area0
Rectangle(2,3) area: 6   Trangle(2,3) area: 3

方法二:使用虚方法

如果要在派生类中重新定义基类的方法, 通常应将基类方法声明为虚的。 这样, 程序将根据对象类型而不是引用或指针的类型来选择方法版本。 为基类声明一个虚析构函数也是一种惯例。

为何基类需要声明一个虚析构函数?

如果析构函数不是虚的, 则将只调用对应于指针类型的析构函数。 如果析构函数是虚的, 将调用相应对象类型的析构函数。

virtual关键字只在类声明时使用(在Shape.h中使用),方法实现中不使用virtual关键字,且基类和派生类中多态方法都要使用virtual关键字

Shape.h

class Shape{
    protected:
        int height, weight;
    public:
        Shape(int h, int w);
    	~Shape(){}	//虚析构函数
        virtual double area();
};

class Rectangle: public Shape{
    public:
        Rectangle(int h, int w);
        virtual double area();
};

class Trangle: public Shape{
    public:
        Trangle(int h, int w);
        virtual double area();
};

重新编译后运行结果如下

shape_r->Rectangle(2,3) area: 6  shape_t->Trangle(2,3) area: 3
Rectangle(2,3) area: 6   Trangle(2,3) area: 3

抽象基类

在原型中使用=0指出类是一个抽象基类, 在基类中可以不定义该函数的实现。

纯虚函数,相当于接口,由派生类演绎

修改Shape.h,将基类中的area定义为纯虚函数

virtual double area() = 0;

则在Shape.cpp中就可以删除基类中对area的函数实现,如果不定义纯虚函数就删除,编译会报错

double Shape::area(){
    cout << "Base Class Area";
    return 0;
}

运行效果同上

标签:area,int,Time,c++,Shape,派生类,OOP,基类
From: https://www.cnblogs.com/dctwan/p/17751959.html

相关文章

  • 如何在visual c++ 6.0中显示行号
    1.下载VC6LineNumberAddin组件,地址:https://pan.baidu.com/s/1rVHL7nQ3Ij0sDkOVUWL_GA下载完后解压后,会有如下3个文件 2.如果你的VC安装在C盘,请拷贝文件VC6LineNumberAddin.dll到安装目录:C:\VC++\MicrosoftVisualStudio\Common\MSDev98\AddIns3.注册双击VC6LineNum......
  • 有效解决VC++6.0一个工程不能有多个main函数的解决方案
    对于初学者来说,需要做很多练习,就需要创建多个main()函数,但C语言只能有一个main()函数,那么通常的做法就是:【方法一】:讲其他文件中的main()函数注释掉,但该方法比较费时费力,不推荐【方法二】:在VC++6.0中,在工程左边fileview里工程下的sourcefiles中,选中前一个带main函数的文件, ......
  • Microsoft Visual C++ 14.0 or greater is required.
    MicrosoftVisualC++14.0orgreaterisrequired.表示缺少VisualStudio2015及以上版本可以通过以下途径解决。最好是第二、三种途径。 一、直接下载对应版本的.whl文件,然后运行pipinstallxxx.whl 二、按照提示去官网下载VisualStudio2015及以上版本都可以,必须安装C++......
  • Visual Studio Code配置C/C++开发环境
    C/C++开发中的IDE非常多,网上有推荐安装VisualStudio2019/2020/2022。但是登录官方网址下载,此软件体积非常大(8G以上),且企业版、专业版会收费。因此,我们推荐大家可以尝试通过VisualStudioCode来配置C/C++开发环境环境准备MinGW-W64,此环境是编译C、C++的源码【必安装】CMake,......
  • C++ 模板特化
    模板特化介绍模板特化是指在模板的基础上,针对某些特定的值,提供一种特殊的实现方式,模板特化分为两种,类模板特化和函数模板特化类模板特化类模板特化指的是在类模板上,针对某些特定的类型和值,提供一种特殊的实现方式。类模板特化分为全特化和偏特化两种。类模板全特化定义......
  • C++提高编程
    C++提高编程本文主要针对C++泛型编程和STL技术做详细讲解,探讨C++更深层的使用1模板1.1模板的概念模板就是建立通用的模具,大大提高复用性例如生活中的模板一寸照片模板:PPT模板:模板的特点:模板不可以直接使用,它只是一个框架模板的通用并不是万能的1.2函数模板......
  • C++基础入门
    C++基础入门1C++初识1.1第一个C++程序编写一个C++程序总共分为4个步骤创建项目创建文件编写代码运行程序1.1.1创建项目​ VisualStudio是我们用来编写C++程序的主要工具,我们先将它打开1.1.2创建文件右键源文件,选择添加->新建项给C++文件起个名称,然后点击添......
  • C++ 使用getline()从文件中读取一行字符串
    我们知道,getline()方法定义在istream类中,而fstream和ifstream类继承自istream类,因此fstream和ifstream的类对象可以调用getline()成员方法。当文件流对象调用getline()方法时,该方法的功能就变成了从指定文件中读取一行字符串。该方法有以下2种语法格式:istream&......
  • VS Code配置C++开发环境(MSVC)
    前置知识这些内容如果感兴趣可以看一下,不看也不妨碍配置环境,因为我会一步步教你配置。(但我希望你还是看一下,毕竟我写了好久......
  • Protobuf在Hadoop RPC中的应用
    ......