类的特性: 封装,继承,多态
封装:
将属性和行为作为一个整体,表现生活中的事务
将属性和行为加以权限控制
语法
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;
}