C++基础(三) 类和对象

文章目录

    • 1 类和对象
    • 2 面向对象和面向过程
        • 2.1 面向对象方式
        • 2.2 面向过程方式
    • 3 计算圆的面积(分开写的形式)
    • 4 对象的构造与析构
        • 4.1 构造函数和析构函数
        • 4.2 "="号运算符重载
        • 4.3 拷贝构造函数
        • 4.4 是否接收匿名对象,影响析构函数的执行时机
        • 4.5 构造函数的初始化列表
        • 4.6 深拷贝和浅拷贝
    • 5 静态成员变量和静态成员函数
        • 5.1 静态成员变量
        • 5.2 静态成员函数
    • 6 this指针
    • 7 成员函数和全局函数
    • 8 友元
        • 8.1 全局友元函数和成员友元函数
        • 8.2 友元类
    • 9 运算符重载
        • 9.1 友元重载
        • 9.2 成员重载
        • 9.3 智能指针

1 类和对象

#include 
using namespace std;

//定义一个类
struct Hero
{
public:
    int sex;
    char name[64];
};

class AdHero
{
public:
    int sex;
    char name[64];
    
    void printHero()
    {
        cout << "性别: " << sex << endl;
        cout << "姓名: " << name << endl;
    }
};

class Animal{
public:
    char color[64];
    char kind[64];
    
    void eat()
    {
        cout << kind << "开始吃了" << endl;
    }
    
    void run()
    {
        cout << kind << "开始跑了" << endl;
    }
};


int main(void){
    //1 通过结构体创建类
    struct Hero MrsHanBing;
    MrsHanBing.sex = 2;
    strcpy(MrsHanBing.name, "寒冰");
    
    cout << "性别: " << MrsHanBing.sex << endl;
    cout << "姓名: " << MrsHanBing.name << endl;
    cout << "==================" << endl;
    
    //2 通过class来创建类
    AdHero MrDeMa;
    MrDeMa.sex = 1;
    strcpy(MrDeMa.name, "德玛");
    
    //通过对象直接调用成员函数
    MrDeMa.printHero();
    cout << "==================" << endl;
    
    //3 示例:对象调用
    Animal dog;
    strcpy(dog.kind, "猪");
    strcpy(dog.color, "白色");
    dog.run();
    dog.eat();
    
    return 0;
}

执行结果

性别: 2
姓名: 寒冰
==================
性别: 1
姓名: 德玛
==================狗开始跑了
狗开始吃了

2 面向对象和面向过程

2.1 面向对象方式

#include 
using namespace std;

class MyDate
{
public:
    int getYear()
    {
        return year;
    }
    
    void init()
    {
        cout << "year, month, day" << endl;
        cin >> year;
        cin >> month;
        cin >> day;
    }
    
    bool isLeapYear()
    {
        if(((year % 4 == 0) && (year % 100 != 0)) || (year % 400 == 0)){
            return true;
        }else{
            return false;
        }
    }
    
    void printDate()
    {
        cout << "日期是" << year << "年" <<month << "月" << day << "日"  << endl;
    }
    
protected:
    int year;
    int month;
    int day;
};

void testClass()
{
    MyDate date;
    
    date.init();
    if(date.isLeapYear() == true){
        cout << date.getYear() << "年是闰年" << endl;
    }else{
        cout << date.getYear() << "年不是闰年" << endl;
    }
}

int main(void){
    testClass();
    return 0;
}

执行结果

year, month, day
2019
5
9
2019年不是闰年

2.2 面向过程方式

#include 
using namespace std;

//1 使用结构体的方式
struct Date{
    int year;
    int month;
    int day;
};

void init(struct Date &date)
{
    cout << "year, month, day" << endl;
    cin >> date.year;
    cin >> date.month;
    cin >> date.day;
}

void printDate(struct Date &date)
{
    cout << "日期是" << date.year << "年" << date.month << "月" << date.day << "日"  << endl;
}

bool isLeapYear(struct Date &date)
{
    if(((date.year % 4 == 0) && (date.year % 100 != 0)) || (date.year % 400 == 0)){
        return true;
    }else{
        return false;
    }
}

void testStruct()
{
    struct Date date;
    init(date);
    printDate(date);
    
    if(isLeapYear(date) == true){
        cout << "是闰年" << endl;
    }else{
        cout << "不是闰年" << endl;
    }
}
int main(void){
    testStruct();
    return 0;
}

执行结果

year, month, day
2020
5
9
日期是2020年5月9日
是闰年

3 计算圆的面积(分开写的形式)

Circle.hpp文件

#ifndef Circle_hpp
#define Circle_hpp
class Circle
{
public:
    void setR(double r);
    double getR();
    double getArea();
    double getGirth();
private:
    double m_r;
};

#endif /* Circle_hpp */

Circle.cpp文件

#include "Circle.hpp"

void Circle::setR(double r)
{
    m_r = r;
}

double Circle::getR()
{
    return m_r;
}

double Circle::getArea()
{
    return m_r * m_r * 3.14;
}

double Circle::getGirth()
{
    return m_r * 3.14 * 2;
}

main.cpp文件

#include 
#include "Circle.hpp"
using namespace std;

int main(){
    Circle circle;
    circle.setR(15.0);
    
    cout  << "圆的面积为: " << circle.getArea() << endl;
    cout  << "圆的周长为: " << circle.getGirth() << endl;
    return 0;
}

执行结果

圆的面积为: 706.5
圆的周长为: 94.2

4 对象的构造与析构

#include 
using namespace std;

class Test
{
public:
    //1 如果不显示提供构造函数,系统就会调用默认的无参构造函数
    
    Test(){
        cout << "执行了构造函数 Test()" << endl;
        m_x = 0;
        m_y = 0;
        p = (char*)malloc(100);
        strcpy(p, "test");
    }

    Test(int x, int y){
        cout << "执行了构造函数 Test(int x, int y)" << endl;
        m_x = x;
        m_y = y;
        p = (char*)malloc(100);
    }
    
    //2 如果不显示提供拷贝构造函数,系统就会调用默认的无参拷贝构造函数
    Test(const Test& test)
    {
        m_x = test.m_x;
        m_y = test.m_y;
        cout << "执行了拷贝构造函数 Test(const Test& test)" << endl;
    }
	
	//1 如果不显示提供析构函数,系统就会调用默认的析造函数
    ~Test()
    {
        cout << "m_x = " << m_x  << "执行了析构函数 ~Test()" << endl;
        
        //2 释放指针示例
        if(p != NULL){
            cout <<"p的堆空间被释放了" << endl;
            free(p);
            p = NULL;
        }
    }

    void printT()
    {
        cout << " x = " << m_x << ", y = " << m_y << endl;
    }
    
    //3 重载等号操作符
    void operator = (const Test &t)
    {
        m_x = t.m_x;
        m_y = t.m_y;
    }

private:
    int m_x;
    int m_y;
    char *p = nullptr;

};

4.1 构造函数和析构函数

void test1(){
    cout << "========== (1) 测试构造函数和析构函数 ==========" << endl;
    //1 调用有参数构造和函数
    Test t1(10, 20);
    t1.printT();
    
    cout << "==================" << endl;
    Test t2;
    t2.printT();
    cout << "==================" << endl;
    
    

    //2 t是局部变量,生命周期和test函数一样,
    //test函数执行完毕会销毁t变量,在t变量销毁之前,会默认调用t的析构函数
    
    //3 析构函数和构造函数执行的顺序相反,即先构造的后析构
}

执行结果

========== (1) 测试构造函数和析构函数 ==========
执行了构造函数 Test(int x, int y)
 x = 10, y = 20
==================
执行了构造函数 Test()
 x = 0, y = 0
==================
m_x = 0执行了析构函数 ~Test()
p的堆空间被释放了
m_x = 10执行了析构函数 ~Test()
p的堆空间被释放了

4.2 "="号运算符重载

void test2(){
    cout << "========== (2) 测试调用=号重载操作符 ==========" << endl;
    Test t1(10, 30);
    Test t2;
    t2.printT();
    t2 = t1;
    t2.printT();
}

执行结果

========== (2) 测试调用=号重载操作符 ==========
执行了构造函数 Test(int x, int y)
执行了构造函数 Test()
 x = 0, y = 0
 x = 10, y = 30
m_x = 10执行了析构函数 ~Test()
p的堆空间被释放了
m_x = 10执行了析构函数 ~Test()
p的堆空间被释放了

4.3 拷贝构造函数

void test3(){
    cout << "========== (3) 拷贝构造函数 ==========" << endl;
    Test t1(20, 30);
    Test t2(t1);
    t2.printT();
}

执行结果

========== (3) 拷贝构造函数 ==========
执行了构造函数 Test(int x, int y)
执行了拷贝构造函数 Test(const Test& test)
 x = 20, y = 30
m_x = 20执行了析构函数 ~Test()
m_x = 20执行了析构函数 ~Test()
p的堆空间被释放了

4.4 是否接收匿名对象,影响析构函数的执行时机

Test func()
{
    cout << "func begin" << endl;
    Test temp(5, 15);
    cout << "func end" << endl;
    return temp;
}

void test4()
{
    cout << "========== (4) 不接收临时变量 析构函数的执行时机测试 ==========" << endl;
    cout << "test4 begin" << endl;
    func();
    //匿名对象在此时机被析构了,如果一个临时的匿名对象,没有任何变量去接收他,
    //编译器认为这个临时匿名变量对象没有用处,会立刻销毁这个临时的匿名对象
    cout << "test4 end" << endl;
}

void test5()
{
    cout << "========== (5) 接收临时变量 析构函数的执行时机测试 ==========" << endl;
    cout << "test5 begin" << endl;
    Test t = func();
    //如果用一个变量去接收这个临时匿名对象,则不会立刻销毁临时变量
    cout << "test5 end" << endl;
    //此时才会销毁
}

执行结果

========== (4) 不接收临时变量 析构函数的执行时机测试 ==========
test4 begin
func begin
执行了构造函数 Test(int x, int y)
func end
m_x = 5执行了析构函数 ~Test()
p的堆空间被释放了
test4 end
========== (5) 接收临时变量 析构函数的执行时机测试 ==========
test5 begin
func begin
执行了构造函数 Test(int x, int y)
func end
test5 end
m_x = 5执行了析构函数 ~Test()
p的堆空间被释放了

4.5 构造函数的初始化列表

#include 
using namespace std;

class A
{
public:
    A(int a)
    {
        m_a = a;
        cout << "a = " << m_a << ", 执行了构造函数" << endl;
    }
    
    ~A()
    {
        cout << "a = " << m_a << ", 执行了析构函数" << endl;
    }
    
    void printA()
    {
        cout << "a = " << m_a << endl;
    }
private:
    int m_a;
};

class B
{
public:
    B(int b, int a1, int a2) : a1(a1), a2(a2)
    {
        m_b = b;
        cout << "b = " << m_b << ", 执行了构造函数" << endl;
    }
    
    void printB(){
        cout << "b = " << m_b << endl;
        a1.printA();
        a2.printA();
    }
private:
    int m_b;
    A a1;
    A a2;
};


void test(){
    A a(10);
    cout << "===================" << endl;
    
    B b(10, 20, 30);
    b.printB();
}
int main(void){
    test();
    return 0;
}

执行结果

a = 10, 执行了构造函数
===================
a = 20, 执行了构造函数
a = 30, 执行了构造函数
b = 10, 执行了构造函数
b = 10
a = 20
a = 30
a = 30, 执行了析构函数
a = 20, 执行了析构函数
a = 10, 执行了析构函数

4.6 深拷贝和浅拷贝

#include 
using namespace std;

class Teacher
{
public:
    //1 构造函数的深拷贝
    Teacher(int id, char *name)
    {
        cout << "Teacher(int id, char *name)" << endl;
        m_id = id;
        int len = strlen(name);
        m_name = (char *)malloc(len + 1);
        strcpy(m_name, name);
    }
    
    //2 拷贝构造函数的深拷贝
    Teacher(const Teacher &another)
    {
        cout << "Teacher(const Teacher &another)" << endl;
        m_id = another.m_id;
        int len = strlen(another.m_name);
        m_name = (char *)malloc(len + 1);
        strcpy(m_name, another.m_name);
    }
    
    ~Teacher()
    {
        if(m_name != NULL){
            free(m_name);
            cout << "~Teacher()" << endl;
        }
    }
    
private:
    int m_id;
    char *m_name;
};

int main(void){
    Teacher t1(2, "张三");
    
    Teacher t2(t1);
    return 0;
}

执行结果

Teacher(int id, char *name)
Teacher(const Teacher &another)
~Teacher()
~Teacher()

如果不在构造函数中,重新开辟空间来存储name值,则在析构函数中会直接崩溃。此为浅拷贝。

5 静态成员变量和静态成员函数

5.1 静态成员变量

#include 
using namespace std;

class Box
{
public:
    Box(int l, int w): length(l),width(w){}

    int volume(){
        return length * width * height;
    }
    

    int length;
    int width;
    static int height;
};

//1 在类的外部初始化
int Box::height = 20;

int main(void){
    
    //赋值方式1
    Box::height = 50;
    
    Box b1(10, 20);
    Box b2(30, 40);
    
    //赋值方式2
    b1.height = 60;
    
    //2 静态变量的在全局范围内的值都是一样的
    cout << "b1.volume()  = " << b1.volume() << ", b1.height = " << b1.height << endl;
    cout << "b2.volume()  = " << b2.volume() << ", b2.height = " << b2.height << endl;
    
    //3 说明static修饰的成员变量并不占用对象的内存空间,而是全局区的空间
    cout << "sizeof(b1) = " << sizeof(b1) << endl;
    
    return 0;
}

执行结果

b1.volume()  = 12000, b1.height = 60
b2.volume()  = 72000, b2.height = 60
sizeof(b1) = 8

5.2 静态成员函数

#include 
using namespace std;

//静态函数用法示例
class Student
{
public:
    Student(int num, double score) : m_num(num), m_score(score)
    {
        count ++;
        sum_score += score;
    }
    
    static double getAvg()
    {
        return sum_score / count;
    }
    
private:
    int m_num;
    double m_score;
    
    static int count;
    static double sum_score;
};

//1 静态变量初始化
int Student::count = 0;
double Student::sum_score = 0;

int main(void){
    
    Student s1(1, 30);
    Student s2(2, 30);
    Student s3(3, 90);
    
    double avg = Student::getAvg();
    
    cout << "学生的平均分数为: " << avg <<endl;
    
    return 0;
}

执行结果

学生的平均分数为: 50

6 this指针

#include 
using namespace std;

class Test
{
public:
    //1 隐式传递this指针
    Test(int k){ //---> Test(Test* this, int k)
        this -> m_k = k;
        this -> m_q = 0;
    }
    
    Test(int k, int q)
    {
        this->m_k = k;
        this->m_q = q;
    }
    
    int getK(Test *test)const // ---> int getK(const Test* const this)
    {
        //2 在成员函数后面加const 表示该函数不能修改该类的任何变量的值
        //m_k++; //Error: Cannot assign to non-static data member within const member function 'getK'
        
        //3  this是一个常指针
        //this++;//Error:Expression is not assignable
        return this->m_k;
    }
    
    void print(){
        cout << "m_k = " << m_k << ", m_q = " << m_q << endl;
    }
    
private:
    int m_k;
    int m_q;
    
};

int main(void){
    
    Test t1(10);//  --->  Test t2(&t1, 10);
    t1.print();
    
    return 0;
}

执行结果

m_k = 10, m_q = 0

7 成员函数和全局函数

#include 
using namespace std;

class Test
{
public:
    Test(int a):m_a(a)
    {
    
    }
    
    //1 成员函数实现 "+" 操作
    Test add(Test &another){
    	//5 同类之间无私处
        Test temp(this->m_a + another.m_a);
        return temp;
    }
    
    //2 成员函数打印m_a值
    void printValue()
    {
        cout << "m_a = " << m_a << endl;
    }
    
    int getA()
    {
        return m_a;
    }
    
private:
    int m_a;
};

//3 全局函数实现 "+" 操作
Test add(Test t1, Test t2){
    Test test(t1.getA() + t2.getA());
    return test;
}

//4 全局函数打印m_a值
void printValue(Test &test){
    cout << "test.getA() = " << test.getA() << endl;
}

int main(void){
    Test t1(20);
    
    Test t2(30);
    Test t3 = t1.add(t2);
    t3.printValue();
    
    Test t4 = add(t2, t3);
    printValue(t4);
    
    return 0;
}

执行结果

m_a = 50
test.getA() = 80

8 友元

8.1 全局友元函数和成员友元函数

#include 
#include 
using namespace std;

class Point;

class PointManager
{
public:
    //1 解决循环前置声明问题,将函数的声明和函数的定义分开
    double pointDistance(Point &p1, Point &p2);
};

class Point
{
public:
    Point(int x, int y)
    {
        this->x = x;
        this->y = y;
    }
    
    void printPoint()
    {
        cout << "" << x << ", y = " << y << endl;
    }
    
    int getX()
    {
        return this->x;
    }
    
    int getY()
    {
        return this->y;
    }
    
    //2 声明一个全局的函数作为友元函数
    friend double pointDistance(Point &p1, Point &p2);
    
    //3 声明一个成员函数作为自己的友元
    friend double PointManager::pointDistance(Point &p1, Point &p2);
private:
    int x;
    int y;
};

//成员函数
double PointManager::pointDistance(Point &p1, Point &p2)
{
    //4 如果不在在Point类中声明当前函数为友元函数,则会报错Error:'x' is a private member of 'Point'
    int dd_x = p1.x - p2.x;
    int dd_y = p1.y - p2.y;
    
    double value = sqrt(dd_x * dd_x + dd_y * dd_y);
    
    cout << "成员函数计算两点之间距离 value = " << value << endl;
    return value;
}

//全局函数
double pointDistance(Point &p1, Point &p2)
{
    //5 如果不在在Point类中声明当前函数为友元函数,则会报错Error:'x' is a private member of 'Point'
    int dd_x = p1.x - p2.x;
    int dd_y = p1.y - p2.y;
    
    double value = sqrt(dd_x * dd_x + dd_y * dd_y);
    
    cout << "全局函数计算两点之间距离 value = " << value << endl;
    return value;
}


int main(void){
    Point p1(2, 2);
    
    Point p2(3, 3);
    
    PointManager pointManager;
    pointManager.pointDistance(p1, p2);
    
    pointDistance(p1, p2);
    return 0;
}

执行结果

成员函数计算两点之间距离 value = 1.41421
全局函数计算两点之间距离 value = 1.41421

8.2 友元类

#include 
using namespace std;

class B;

class A
{
public:
    A(int a)
    {
        this->m_a = a;
    }
    
    void printB(B &b)
    {
        // Member access into incomplete type 'B'
        // cout << "b.m_b = " << b.m_b << endl;
    }
    
    //1 声明类B为自己的友元类,这样就能在类B中访问私有成员变量和方法
    friend class B;
private:
    int m_a;
};

class B
{
public:
    B(int b)
    {
        this->m_b = b;
    }
    
    //2 如果不在A类中声明B为友元类,则会报错 Error:'m_a' is a private member of 'A'
    void printA(A &a)
    {
        cout << "a.m_a = " << a.m_a << endl;
    }
    
    friend class A;
    
private:
    int m_b;
};


int main(void){
    
    A a(10);
    B b(20);
    
    b.printA(a);
    return 0;
}

执行结果

a.m_a = 10

9 运算符重载

9.1 友元重载

#include 
using namespace std;

class Complex
{
public:
    
    Complex(int a, int b) : m_a(a), m_b(b)
    {
        this->m_a = a;
        this->m_b = b;
    }
    
    void printValue()
    {
        cout << "m_a = " << m_a << ", m_b = " << m_b << endl;
    }
    
    friend const Complex operator+(const Complex &c1, const Complex &c2);
    
    private:
        int m_a;
        int m_b;
};

//友元重载
const Complex operator+(const Complex &c1, const Complex &c2)
{
    return Complex(c1.m_a + c2.m_a, c1.m_b + c2.m_b);
}

int main(void){
    
    Complex complex1(10, 20);
    Complex complex2(20, 70);
    
    //1 友元重载
    Complex complex3 = complex1 + complex2;
    complex3.printValue();
    
    return 0;
}

执行结果

m_a = 30, m_b = 90
m_a = 10, m_b = 50

9.2 成员重载

在类中添加重载函数,并注释掉全局重载函数
//重载+
    Complex operator+(Complex &another)
    {
        Complex temp(this->m_a + another.m_a, this->m_b + another.m_b);
        return temp;
    }

//重载-
    Complex operator-(Complex &another)
    {
        Complex temp(this->m_a - another.m_a, this->m_b - another.m_b);
        return temp;
    }
    
int main(void){
    Complex complex1(10, 20);
    Complex complex2(20, 70);

    Complex complex3 = complex2 + complex1;
    complex3.printValue();
    
    complex3 = complex2 - complex1;
    complex3.printValue();
    
    return 0;
}

执行结果

m_a = 30, m_b = 90
m_a = 10, m_b = 50

9.3 智能指针

#include 
using namespace std;

class A{
public:
    A()
    {
        cout << " A()" << endl;
    }
    
    ~A()
    {
        cout << " ~A()" << endl;
    }
    
    void printMethod()
    {
        cout << "printMethod" << endl;
    }
};

class PMA
{
public:
    PMA(A *p) :_p(p)
    {
        
    }
    
    ~PMA()
    {
        if(this->_p != NULL)
        {
            delete _p;
        }
    }
    
    A& operator*()
    {
        return *_p;
    }
    
    A* operator->()
    {
        return _p;
    }
private:
    A* _p;
};

void test()
{
    PMA auto_p(new A);
    auto_p->printMethod();
    (*auto_p).printMethod();
    
}

int main(void){
    test();
    return 0;
}

执行结果

 A()
printMethod
printMethod
 ~A()

你可能感兴趣的:(c++)