C++——类和对象

简介: C++——类和对象

文章目录

类和对象

什么是对象

如何描述对象

面向对象编程

什么是类

类的定义和实例化

类的语法形式

对象的创建和销毁

构造函数和初始化表

代码示例


类和对象

什么是对象

万物皆对象,任何一种事物都可以看做是对象。


如何描述对象

通过对象的属性(名词、数量词、形容词)和行为(动词)来描述对象。

例如:描述冰箱对象


  • 属性:品牌、容量、颜色、功耗。。。。
  • 行为:冷冻、冷藏、装东西。

面向对象编程

对自然世界中对象的观察引入到编程实践的一种理念和方法,这种方法称为“数据抽象”,即在描述对象时把细节的东西剥离出去,只考虑一般性的、有规律性的、统一性的东西。


什么是类

类是将多个对象的共性提取出来定义的一种新的数据类型,是对对象属性和行为的抽象描述。

现实世界到类到编程世界

具体对象–抽象–>属性/行为–实例化–>具体对象


类的定义和实例化

类的语法形式

struct/class 类名:继承方式  基类{
  访问控制限定符:
    类名(形参表):初始化表{...}//构造函数
    ~类名(void){...}  //析构函数
    返回类型 函数名(形参表){} //成员函数
    数据类型 变量名;//成员变量
  };


访问控制限定符:影响类中成员的访问位置


  1. public:公有成员,在任何位置都可以访问。
  2. private:私有成员,只有类的内部才能访问。
  3. protected:保护成员。

构造函数(constructor)

语法:


class 类名{
  类名(构造形参表){
  //主要负责初始化对象,即初始化成员变量
  }
};


  • 函数名与类名相同,没用返回类型。
  • 构造函数在创建对象时自动被调用和执行,不能像普通的成员函数通过对象去调用。

对象的创建和销毁

  • 在栈区创建单个对象
类名 对象(构造实参表); 
  类名 对象 = 类名(构造实参表);

  • 在栈区创建多个对象(对象数组)
类名 对象数组[元素个数] = {
  类名(构造实参表),类名(构造实参表),...};

  • 在堆区创建/销毁单个对象
创建:类名* 对象指针 = new 类名(构造实参表);
销毁:delete 对象指针;

  • 在堆区创建/销毁多个对象(对象数组)
创建:
  类名* 对象指针 = new 类型[元素个数]{
  类名(构造实参表),类名(构造实参表),...};
销毁:
  delete[] 对象指针;

构造函数和初始化表

  • 构造函数可以重载、可以带有缺省参数
  • 缺省构造函数(无参构造函数)
  • 如果一个类没用定义构造函数,编译器会提供一个缺省(无参)构造函数。(对基本类型的成员变量不做初始化,对类、类型的成员变量会自动调用相应的类的无参构造函数来初始化)
  • 如果自己定义了构造函数,无论是否有参数,编译器都不会再提供缺省的构造函数了。
  • 类型转换构造函数(单参构造函数)
class 目标类型{
  [explicit] 目标类型(源类型){...}
  };
  可以实现源类型到目标类型的隐式转换。
  注:使用explicit关键字,可以强制这种转换必须显式的完成。

  • 拷贝(复制)构造函数
  • 用一个已存在的对象构造同类型的副本对象时,会调用该类的拷贝构造函数。
  • 如果一个类中没用定义拷贝构造函数,那么编译器会为其提供一个缺省的拷贝构造函数。(对基本类型成员变量按字节复制;对类类型成员变量(成员子对象),自动调用相应类型的拷贝构造函数,多数情况下不需要自己写拷贝构造函数,因为编译器缺省提供的拷贝构造函数已经很好使用了。)
  • 拷贝构造函数调用时机:用已存在的对象作为同类对象的构造实参;以对象的形式向函数传递参数;从函数中反悔对象(可能被编译器优化掉)
class 类名{
    类名(const 类名&){...}
   };
  eg:
  class A{...};
  A a1;
  A a2(a1);//调用拷贝构造函数

  • 初始化表
  • 如果有类、类型成员变量(成员子对象),而该类又没用无参构造函数,则必须使用初始化表来初始化该成员变量。
class 类名{
  类名(形参表):成员变量(初值),...{}
  };

代码示例

  • constructor.cpp
#include <iostream>
using namespace std;
class Student{
public:
    Student(const string& name,int age,
            int no){
        cout << "构造函数" << endl;
        m_name = name;
        m_age = age;
        m_no = no;
    }
    void who(void){
        cout << "我叫" << m_name << ",今年"
            << m_age << "岁,学号是" << m_no
            << endl;
    }
private:
    string m_name;
    int m_age;
    int m_no;
};
int main(void)
{
    //创建对象,实例化对象,构造对象
    //(...),指明构造函数需要的实参
    Student s("李辉",35,10011);
    s.who();
    //构造函数不能想普通成员函数一样去调用
    //s.Student("李三",36,10012);
    return 0;
}


  • 执行结果

20200212084341137.png

  • clock.cpp
#include <iostream>
#include <cstdio>
#include <ctime>
#include <unistd.h>
class Clock{
public:
    Clock(time_t t){
        tm* local = localtime(&t);
        m_hour = local->tm_hour;
        m_min = local->tm_min;
        m_sec = local->tm_sec;
    }
    void run(void){
        while(1){
            printf("\r%02d:%02d:%02d",
                    m_hour,m_min,m_sec);
            fflush(stdout);//刷新输出缓冲区
            if(++m_sec == 60){
                m_sec = 0;
                if(++m_min == 60){
                    m_min = 0;
                    if(++m_hour == 24)
                        m_hour = 0;
                }
            }
            sleep(1);
        }
    }
private:
    int m_hour;
    int m_min;
    int m_sec;
};
int main(void)
{
    Clock c(time(0));
    c.run();
    return 0;
}


  • 执行结果

20200212085222115.png

  • 02constructor.cpp
#include <iostream>
using namespace std;
class Student{
public:
    Student(const string& name,int age,
            int no){
        cout << "构造函数" << endl;
        m_name = name;
        m_age = age;
        m_no = no;
    }
    void who(void){
        cout << "我叫" << m_name << ",今年"
            << m_age << "岁,学号是" << m_no
            << endl;
    }
private:
    string m_name;
    int m_age;
    int m_no;
};
int main(void)
{
    //创建对象,实例化对象,构造对象
    //(...),指明构造函数需要的实参
    //Student s("李辉",35,10011);
    //和上面等价
    Student s = Student("李辉",35,10011);
    s.who();
    //栈区创建对象数组
    Student sarr[3] = {
        Student("白骨精",19,10012),
        Student("林黛玉",18,10013),
        Student("潘金莲",20,10014)};
    sarr[0].who();
    sarr[1].who();
    sarr[2].who();
    //在堆区创建单个对象
    Student* ps = 
        new Student("貂蝉",17,10015);
    ps->who();//(*ps).who()
    delete ps;
    ps = NULL;
    //在堆区创建多个对象,c++11
    Student* parr = new Student[3]{
        Student("小乔",28,10016),
        Student("大乔",29,10017),
        Student("西施",30,10018)};
    parr[0].who();//(*(parr+0)).who()
    parr[1].who();
    parr[2].who();
    delete[] parr;
    parr = NULL;
    return 0;
}


  • 执行结果

20200212085958843.png

  • defCons.cpp

#include <iostream>
using namespace std;
class A{
public:
    A(void){
        cout << "A的无参构造函数" << endl;
        m_data = 12345;
    }
    int m_data;
};
class B{
public:
    //B(int num){}
    int m_num;//基本类型
    A m_a;//类 类型(成员子对象)
};
int main(void)
{
    B b;
    cout << b.m_num << endl;//?
    cout << b.m_a.m_data << endl;//12345
    return 0;
}


  • 执行结果

20200212092142407.png

  • castCons.cpp
#include <iostream>
using namespace std;
class Integer{
public:
    Integer(void){
        cout << "Integer(void)" << endl;
        m_data = 0;
    }
    //int->Integer
    //类型转换构造函数
    /*explicit*/ Integer(int data){
        cout << "Integer(int)" << endl;
        m_data = data;
    }
    void print(void){
        cout << m_data << endl;
    }
private:
    int m_data;
};
int main(void)
{
    Integer i;
    i.print();//0
    //1)自动调用类型转换构造函数,用123作为
    //构造实参创建一个临时对象
    //2)再用临时对象给i进行赋值操作
    i = 123;
    i.print();//123
    //使用类型转换构造函数实现的隐式转换代码
    //可读性差,推荐使用显式转换
    //i = (Integer)321;//C风格
    i = Integer(321);//C++风格
    i.print();//321
    return 0;
}


  • 执行结果

20200212095102794.png

  • cpCons.cpp


#include <iostream>
using namespace std;
class A{
public:
    A(int data = 0){
        cout << "A(int=0)" << endl;
        m_data = data;
    }
    //拷贝构造函数
    A(const A& that){
        cout << "A(const A&)" << endl;
        m_data = that.m_data;    
    }
    int m_data;
};
int main(void)
{
    const A a1(12345);
    A a2(a1);
    //A a2 = a1;//和上面写法完全等价
    cout << a1.m_data << endl;
    cout << a2.m_data << endl;
    return 0;
}


  • 执行结果

20200212095406860.png

  • 02cpCons.cpp
#include <iostream>
using namespace std;
class A{
public:
    A(int data = 0){
        cout << "A(int)" << endl;
        m_data = data;
    }
    A(const A& that){
        cout << "A(const A&)" << endl;
        m_data = that.m_data;
    }
    int m_data;
};
class B{
public:
    A m_a;//成员子对象
};
int main(void)
{
    B b;
    b.m_a.m_data = 12345;
    B b2(b);//拷贝构造
    cout << b.m_a.m_data << endl;//12345
    cout << b2.m_a.m_data << endl;//12345
    return 0;
}


  • 执行结果

2020021209563056.png

  • 03cpCons.cpp
#include <iostream>
using namespace std;
class A{
public:
    A(void){
        cout << "A(void)" << endl;
    }
    A(const A& that){
        cout << "A(const A&)" << endl;
    }
};
void foo(A a){}
A bar(void){
    A a;//无参
    cout << "&a=" << &a << endl; 
    return a;//拷贝
}
int main(void)
{
    A a1;//无参
    A a2 = a1;//拷贝
    foo(a1);//拷贝
    /* 正常情况bar返回a拷贝到临时对象,临时
     * 对象再拷贝到a3,发生两次拷贝;但是因
     * 为编译器优化,让a3直接引用a,不再发生
     * 拷贝*/
    //去优化的选项
    //g++ xx.cpp -fno-elide-constructors
    A a3 = bar();//拷贝
    cout << "&a3=" << &a3 << endl;
    return 0;
}


  • 执行结果

20200212100140139.png

  • initlist.cpp
#include <iostream>
using namespace std;
class Student{
public:
    //先把成员变量定义出来(内存分配)
    //再执行构函数函数体,赋初值
    /*Student(const string& name,int age,
            int no){
        cout << "构造函数" << endl;
        m_name = name;
        m_age = age;
        m_no = no;
    }*/
    //使用初始化表:定义成员变量同时初始化
    Student(const string& name,int age,
        int no):m_name(name),m_age(age),
                m_no(no){}
    void who(void){
        cout << "我叫" << m_name << ",今年"
            << m_age << "岁,学号是" << m_no
            << endl;
    }
private:
    string m_name;
    int m_age;
    int m_no;
};
int main(void)
{
    //创建对象,实例化对象,构造对象
    //(...),指明构造函数需要的实参
    Student s("李辉",35,10011);
    s.who();
    return 0;
}


  • 执行结果

20200212100531720.png

  • 02initlist.cpp
#include <iostream>
using namespace std;
class A{
public:
    A(int data){
        cout << "A的构造函数" << endl;
        m_data = data;
    }
    int m_data;
};
class B{
public:
    //:m_a(..),显式指明成员子对象m_a的
    //初始化方式
    B(void):m_a(12345){
        cout << "B的构造函数" << endl;
    }
    A m_a;
};
int main(void)
{
    B b;
    return 0;
}


  • 执行结果

20200212100850496.png

企业员工类emloyee

  • employee.cpp
#include <iostream>
using namespace std;
class Employee{
public:
    void printInfo(void){
        cout << "姓名:" << m_name << endl;
        cout << "工号:" << m_id << endl;
        cout << "基础工资:"  << m_salary << endl;
    }
    void calSalary(void){
        cout << "请输入出勤天数:";
        int days;
        cin >> days;
        double basic = m_salary * (days/23.0);
        double merit = basic / 2;
        cout << "总工资:" << 
            (basic + merit) << endl;
    }
public:
    void setId(int id){
        if(id<10000)
            cout << "无效的工号" << endl;
        else
            m_id = 10011;
    }
    void setName(const string& name){
        if(name.size() > 20)
            cout << "无效的姓名" << endl;
        else
            m_name = name;
    }
    void setSalary(double salary){
        if(salary<0)
            cout << "无效的工资" << endl;
        else
            m_salary = salary;
    }
private:
    int m_id;//工号
    string m_name;//姓名
    double m_salary;//工资
};
int main()
{
    Employee emp;
    emp.setId(10011);
    emp.setName("张三");
    emp.setSalary(6600);
    emp.printInfo();
    emp.calSalary();
    return 0;
}


  • 执行结果

20200212101837462.png

相关文章
|
1月前
|
编译器 C++
C++之类与对象(完结撒花篇)(上)
C++之类与对象(完结撒花篇)(上)
34 0
|
4天前
|
存储 编译器 C++
【c++】类和对象(中)(构造函数、析构函数、拷贝构造、赋值重载)
本文深入探讨了C++类的默认成员函数,包括构造函数、析构函数、拷贝构造函数和赋值重载。构造函数用于对象的初始化,析构函数用于对象销毁时的资源清理,拷贝构造函数用于对象的拷贝,赋值重载用于已存在对象的赋值。文章详细介绍了每个函数的特点、使用方法及注意事项,并提供了代码示例。这些默认成员函数确保了资源的正确管理和对象状态的维护。
22 4
|
6天前
|
存储 编译器 Linux
【c++】类和对象(上)(类的定义格式、访问限定符、类域、类的实例化、对象的内存大小、this指针)
本文介绍了C++中的类和对象,包括类的概念、定义格式、访问限定符、类域、对象的创建及内存大小、以及this指针。通过示例代码详细解释了类的定义、成员函数和成员变量的作用,以及如何使用访问限定符控制成员的访问权限。此外,还讨论了对象的内存分配规则和this指针的使用场景,帮助读者深入理解面向对象编程的核心概念。
18 4
|
28天前
|
存储 编译器 对象存储
【C++打怪之路Lv5】-- 类和对象(下)
【C++打怪之路Lv5】-- 类和对象(下)
25 4
|
28天前
|
编译器 C语言 C++
【C++打怪之路Lv4】-- 类和对象(中)
【C++打怪之路Lv4】-- 类和对象(中)
20 4
|
28天前
|
存储 安全 C++
【C++打怪之路Lv8】-- string类
【C++打怪之路Lv8】-- string类
19 1
|
29天前
|
存储 编译器 C语言
【C++打怪之路Lv3】-- 类和对象(上)
【C++打怪之路Lv3】-- 类和对象(上)
15 0
|
1月前
|
编译器 C++ 数据库管理
C++之类与对象(完结撒花篇)(下)
C++之类与对象(完结撒花篇)(下)
29 0
|
1月前
|
编译器 C++
C++之类与对象(3)(下)
C++之类与对象(3)(下)
32 0
|
1月前
|
存储 编译器 C++
【C++类和对象(下)】——我与C++的不解之缘(五)
【C++类和对象(下)】——我与C++的不解之缘(五)