c++ 语法 类和对象

类的特性: 封装,继承,多态

封装:

将属性和行为作为一个整体,表现生活中的事务

将属性和行为加以权限控制

语法

class 类名{访问权限:属性/行为}

//
//  main.cpp
//  cpplearn
//
//  Created by KING on 2024/2/1.
//

#include <iostream>
#include "mathutil.hpp"
#include <string>
using namespace std;
const double PI = 3.14;
class Circle {
    //访问权限
    
public:
    //属性
    double m_r;
    //行为
    double caculate() {
        return 2 * m_r * PI;
    }
    
};

class Person {
    // 属性 成员属性 成员变量
    //行为 成员函数 方法
private:
    string m_name;
    int  cardId;
    int  m_age;
public:
    
    string getName() {
        return m_name;
    }
    
    int getCardId() {
        return cardId;
    }
    
    void personInfo() {
        std::cout << m_name << "cardID =" << cardId << std::endl;
    }
    
    void setAge(int age) {
        if (age < 0 || age > 150) {
            std::cout << "age shu ru you  wu" << std::endl;
            return;
        }
        m_age = age;
        
    }
    void setName(string name) {
        m_name = name;
    }
    void setId(int id) {
        cardId = id;
    }
};


int main(int argc, const char * argv[]) {
    // insert code here...
    std::cout << "Hello, World!\n";
    // 实例化 通过类创建对象
    Circle c1;
    //属性赋值
    c1.m_r = 10;
    std::cout << "周长=" << c1.caculate() << std::endl;
    Person person;
    person.setName("李斯");
    person.setId(411323);
    person.personInfo();
    std::cout << person.getName() << "cardID =" << person.getCardId() << std::endl;

    return 0;
}

权限

public: 公共权限:类内类外都可访问

protected  保护权限:类内可以访问 类外不可访问 子类可访问父类保护属性

private 私有权限:类内可以访问 类外不可以访问 子类不能访问父类私有属性

struct 和 class的区别

struct默认权限为公共

class默认权限为私有

demo

#include <iostream>
#include "mathutil.hpp"
#include <string>
using namespace std;
class  Cube{
private:
    double m_width;
    double m_height;
    double m_length;
public:
    void setHeight(double height) {
        m_height = height;
    }
    void setWidth(double width) {
        m_width = width;
    }
    void setLength(double length){
        m_length = length;
    }
    double getWidth() {
        return m_width;
    }
    double getHeight() {
        return m_height;
    }
    double getLength() {
        return m_length;
    }
    
    double getarea() {
        return 2 * m_height * m_width + 2 * m_length * m_height + 2 * m_length * m_width;
    }
    double getcubeaV() {
        return m_width * m_height * m_length;
    }
    bool isSamplecube(Cube &c) {
        if (getWidth() == c.getWidth() && getHeight() == c.getHeight() && getLength() == c.getLength()) {
            return  true;
        }
        return false;
    }

};

bool isSampleCube(Cube &c1, Cube &c2) {
    if (c1.getWidth() == c2.getWidth() && c1.getHeight() == c2.getHeight() && c1.getLength() == c2.getLength()) {
        return  true;
    }
    return false;
}

int main(int argc, const char * argv[]) {
    // insert code here...
    std::cout << "Hello, World!\n";
    Cube cube;
    cube.setWidth(10.0);
    cube.setHeight(13.0);
    cube.setLength(23.0);
    
    std::cout << "面积=" << cube.getarea() << "\t 体积=" << cube.getcubeaV() << std::endl;
    
    Cube cube2;
    cube2.setWidth(10.0);
    cube2.setHeight(13.0);
    cube2.setLength(23.0);
   
    if (isSampleCube(cube, cube2)) {
        std::cout  << "cube == cube2" << std::endl;
    } else {
        std::cout  << "cube != cube2" << std::endl;
    }
    
    Cube cube3;
    cube3.setWidth(11.0);
    cube3.setHeight(16.0);
    cube3.setLength(28.0);
    if (cube2.isSamplecube(cube3)) {
        std::cout  << "cube2 == cube3" << std::endl;
    } else {
        std::cout  << "cube3 != cube2" << std::endl;
    }

    
    return 0;
}

  类内有其他类作为成员变量

   

#include <iostream>
#include "mathutil.hpp"
#include <string>
using namespace std;
class Point {
private:
    double m_x;
    double m_y;
public:
    void setX(double x) {
        m_x = x;
    }
    void setY(double y) {
        m_y = y;
    }
    double getX() {
        return m_x;
    }
    double getY() {
        return m_y;
    }
};
class Circle1 {
private:
    double m_r;
    Point  m_point;
    
public:
    void setR(double r) {
        m_r = r;
    }
    void setPoint(Point point) {
        m_point = point;
    }
    double getR() {
        return m_r;
    }
    
    Point getPoint() {
        return m_point;
    }
};
void isInCircle(Circle1 &circle, Point &point) {
    double distance = (circle.getPoint().getX() - point.getX()) *  (circle.getPoint().getX() - point.getX()) + (circle.getPoint().getY() - point.getY()) * (circle.getPoint().getY() - point.getY());
    double mr = circle.getR() * circle.getR();
    
    if (distance == mr) {
        std::cout << "点在圆上" << std::endl;
    } else if (distance < mr) {
        std::cout << "点在圆内" << std::endl;

    } else {
        std::cout << "点在圆外" << std::endl;
    }
}
int main(int argc, const char * argv[]) {
    // insert code here...
    std::cout << "Hello, World!\n";
    Point center;
    center.setX(10.0);
    center.setY(0.0);
    Circle1 circle;
    circle.setR(10.0);
    circle.setPoint(center);
    
    
    Point point;
    point.setX(-1.0);
    point.setY(0.0);
    
    
    isInCircle(circle, point);
    return 0;
}

构造函数析构函数

构造函数初始化类

析构函数销毁类资源

对象的初始化和清理工作是由编译器强制要求我们做的 因此我们如果不提供构造函数和析构函数编译器会提供 编译器提供的构造和析构函数是空实现

构造函数: 主要用于创建对象时为对象的成员属性赋值 构造函数由编译器自动调用无需手动调用

析构函数: 主要作用于对象销毁前系统自动调用 执行一些清理工作。

构造函数语法:

类名(){}

1.构造函数没有返回值也不用写void

2.函数名称与类名相同

3.构造函数可以有参数 因此可以重载

4.程序在调用对象的时候会自动调用构造函数 无需手动调用 并且只调用一次。

析构函数语法

1.析构函数没有返回值也不用写void

2.函数名称与类名相同在类名前面加上~

3.析构函数有没有参数 因此不可以重载

4.程序对象销毁前会自动调用析构函数 无需手动调用 并且只会调用一次。

.h文件

#ifndef People_hpp
#define People_hpp

#include <stdio.h>
class People {
public:
    People();
    ~People();
    
};


#endif /* People_hpp */

.cpp文件

#include "People.hpp"
#include <iostream>
People:: People() {
    std::cout << "people 构造函数调用了" << std::endl;
}

People:: ~People() {
    std::cout << "people 析构函数调用了" << std::endl;

}
 

调用

#include <iostream>
#include "People.hpp"
using namespace std;
int main(int argc, const char * argv[]) {
    // insert code here...
    std::cout << "Hello, World!\n";
    People people;
    People p = People();
    return 0;
}

构造函数的分类和调用

按参数分类: 有参构造函数和无参构造函数

按类型分类:普通构造函数和拷贝构造函数

调用方式

1.括号调用

2.显式调用

3.隐式转换法

#ifndef People_hpp
#define People_hpp

#include <stdio.h>
class People {
    int m_age;
public:
    // 有参构造
    People(int age);
    //无参构造
    People();
    //拷贝构造
    People(const People  &p);
    ~People();
    
};


#endif /* People_hpp */
#include "People.hpp"
#include <iostream>
//无参构造 或者默认构造函数
People:: People() {
    std::cout << "people 构造函数调用了。无参构造 或者默认构造函数" << std::endl;
}

People:: ~People() {
    std::cout << "people 析构函数调用了" << std::endl;

}
 
// 有参构造
People:: People(int age) {
    m_age = age;
    std::cout << "people 构造函数调用了。  有参构造" << std::endl;
}

//拷贝构造
People:: People(const People &p) {
    m_age = p.m_age;
    std::cout << "people 构造函数调用了。 拷贝构造" << std::endl;

}
#include <iostream>
#include "People.hpp"
using namespace std;
int main(int argc, const char * argv[]) {
    // insert code here...
    std::cout << "Hello, World!\n";
    // 默认构造函数调用
    // 括号调用法
    People p1; // 默认构造函数 注意调用的时候不需要使用小括号 否则编译器会把它当成函数声明People p()
    People p2(25);
    People p3(p2);
    
    //显式法
    People p4 = People(10); // 有参构造
    People p5 = People(p4); // 拷贝构造
    
    //People(22); // 匿名对象 当前行执行结束后系统会立即回收其内存
    // 不要用拷贝对象初始化一个匿名构造函数 编译器会认为是重定义  People(p5)
    
    //隐式转换
    People p6 = 10; //相当于 People p6 = People(10); 有参构造
    People p7 = p6; // 拷贝构造
    return 0;
}
拷贝构造的使用场景

1.使用已经创建完成的对象创建一个新对象

    People p4 = People(10); // 有参构造
    People p5 = People(p4); // 拷贝构造

2.值传递的方式给函数参数传值. (调用函数传值的时候 实参给形参赋值的时候)

#include <iostream>
#include "People.hpp"
using namespace std;
void peopleInfo(People p) {
    std::cout << "peopleInfo!\n" << std::endl;

}
int main(int argc, const char * argv[]) {
    // insert code here...
    std::cout << "Hello, World!\n";
    People p;
    peopleInfo(p);
    return 0;
}








Hello, World!
people 构造函数调用了。无参构造 或者默认构造函数
people 构造函数调用了。 拷贝构造
peopleInfo!

people 析构函数调用了
people 析构函数调用了
Program ended with exit code: 0

3.值返回局部对象

#include <iostream>
#include "mathutil.hpp"
#include <string>
#include "People.hpp"
using namespace std;

People createPeople() {
    People p;
    std::cout <<  &p << std::endl;
    return p;
}
void test22() {
    People p1 = createPeople();
    std::cout <<  &p1 << std::endl;

}
int main(int argc, const char * argv[]) {
    // insert code here...
    std::cout << "Hello, World!\n";
    test22();
    return 0;
}










Hello, World!
people 构造函数调用了。无参构造 或者默认构造函数
0x7ff7bfeff238
0x7ff7bfeff238
people 析构函数调用了
sh: pause: command not found
Program ended with exit code: 0

    我在xcode上没有试出来  可能不同编译器 处理的不同吧

构造函数调用规则

默认情况下cpp给一个类提供三个函数

1.默认构造函数 函数体为空

2.析构函数 函数体为空

3.默认拷贝构造函数 对属性进行值拷贝

规则

如果自定义了有参构造函数 c++不再提供默认构造函数 但是会提供默认拷贝构造函数

如果自定义了拷贝构造函数 c++不再提供其他构造函数。

深浅拷贝

 使用编译器生层的拷贝构造函数 浅拷贝

 这样在析构释放堆区内存的时候就会crash

#ifndef Phone_hpp
#define Phone_hpp

#include <stdio.h>
class Phone {
private:
    double m_width;
    double* m_height;
public:
    Phone(double width,double height);
    ~Phone();
};
#endif /* Phone_hpp */
#include "Phone.hpp"
#include <iostream>

Phone::Phone(double width,double height) {
    m_width = width;
    m_height = new double(height);
    std::cout << "Phone 构造函数调用了。  有参构造" << std::endl;

}

Phone::~Phone() {
    // 清理堆区开辟的内存
    if (m_height != NULL) {
        delete m_height;
        m_height = NULL;
    }
    std::cout << "Phone 析构函数调用了" << std::endl;

}
#include <iostream>
#include "Phone.hpp"
using namespace std;
void test23() {
    Phone phone(16,20);
    Phone p(phone);

}

int main(int argc, const char * argv[]) {
    // insert code here...
    std::cout << "Hello, World!\n";
    
    test23();
    std::cout << "end!\n";

    return 0;
}










Hello, World!
Phone 构造函数调用了。  有参构造
Phone 析构函数调用了
cpplearn(5538,0x7ff85f8bc680) malloc: *** error for object 0x600000010030: pointer being freed was not allocated
cpplearn(5538,0x7ff85f8bc680) malloc: *** set a breakpoint in malloc_error_break to debug
(lldb) 

深拷贝 解决类中有在堆区开辟内存的 一定要自己实现拷贝构造函数 防止浅拷贝析构 释放堆区内存时候crash

#ifndef Phone_hpp
#define Phone_hpp

#include <stdio.h>
class Phone {
private:
    double m_width;
    double* m_height;
public:
    Phone(double width,double height);
    Phone(const Phone &p);
    ~Phone();
};
#endif /* Phone_hpp */
#include "Phone.hpp"
#include <iostream>

Phone::Phone(double width,double height) {
    m_width = width;
    m_height = new double(height);
    std::cout << "Phone 构造函数调用了。  有参构造" << std::endl;

}
/// 当类中有指针类型的时候 就需要自己实现拷贝构造函数
Phone::Phone(const Phone &p) {
    m_width = p.m_width;
    m_height =  new double(*p.m_height);
    std::cout << "Phone 拷贝构造函数调用了。" << std::endl;
}

Phone::~Phone() {
    // 清理堆区开辟的内存
    if (m_height != NULL) {
        delete m_height;
        m_height = NULL;
    }
    std::cout << "Phone 析构函数调用了" << std::endl;

}
#include <iostream>
#include "Phone.hpp"
using namespace std;
void test23() {
    Phone phone(16,20);
    Phone p(phone);

}

int main(int argc, const char * argv[]) {
    // insert code here...
    std::cout << "Hello, World!\n";
    
    test23();
    std::cout << "end!\n";

    return 0;
}









Hello, World!
Phone 构造函数调用了。  有参构造
Phone 拷贝构造函数调用了。
Phone 析构函数调用了
Phone 析构函数调用了
end!
Program ended with exit code: 0

初始化列表

用来初始化属性

构造函数():属性1:(值1)属性2:(值2)...{}

#include <iostream>
#include <string>
using namespace std;
class Car{
private:
    string m_name;
    string m_color;
    double m_version;
public:
    Car(string name, string color, double version): m_name(name), m_color(color), m_version(version) {
        std::cout << "name = " << m_name << "color = " << m_color << "version = " << m_version << std::endl;
    };
    ~Car() {
        std::cout << "~Car()\n";
    }
};




int main(int argc, const char * argv[]) {
    // insert code here...
    std::cout << "Hello, World!\n";
    Car car("bmw","black",8.1);
    std::cout << "end!\n";

    return 0;
}

  • 10
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值