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;
}
  • 执行结果
    在这里插入图片描述
  • 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;
}
  • 执行结果
    在这里插入图片描述
  • 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;
}
  • 执行结果
    在这里插入图片描述
  • 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;
}
  • 执行结果
    在这里插入图片描述
  • 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;
}
  • 执行结果
    在这里插入图片描述
  • 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;
}
  • 执行结果
    在这里插入图片描述
  • 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;
}
  • 执行结果
    在这里插入图片描述
  • 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;
}
  • 执行结果
    在这里插入图片描述
  • 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;
}
  • 执行结果
    在这里插入图片描述
  • 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;
}
  • 执行结果
    在这里插入图片描述
    企业员工类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;
}
  • 执行结果
    在这里插入图片描述
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值