文章目录
- 1.C++何时应该使用`new`,以及何时可以避免使用它
- 2.用delete释放内存,避免内存泄漏
- 3.C++的强制类型转换
- 4.面向对象程序设计思想有三大特征:封装、继承和多态。
- 5.类
- 6.权限控制符
- 7.在C++里,对于一个类的成员变量,如果在其中一个成员函数里被改变值了,那在调用另一个函数时,成员变量的值是什么?
- 8.类的构造函数
- 9.含有成员对象的类的构造函数
- 10.析构函数(释放类的资源)
- 10const常成员变量
- 11.const常成员函数
- 12.Static修饰成员变量和成员函数
- 13.const和static不用在c++的类里去定义成员变量和成员函数,而是用在c里有什么作用?
- 14.普通函数、类成员函数作为“类的友元函数”
- 15 友元类
- 16.运算符重载
- 17.继承
1.C++何时应该使用new
,以及何时可以避免使用它
在C++中,你需要使用new
关键字来分配堆内存(动态内存)为对象或基本数据类型分配空间。当你需要控制对象的生命周期,或者大小在编译时无法确定时,使用new
是必要的。然而,使用new
会引入内存管理的责任,你需要确保每次使用new
分配的内存被delete
释放,以避免内存泄漏。
这里有几种情景,分别描述何时应该使用new
,以及何时可以避免使用它:
何时使用new
:
-
需要在多个函数调用中保持对象状态:如果你的对象需要在函数调用之间保持状态,且不应局限于栈的生命周期,则应使用
new
在堆上分配内存。 -
大型对象或数组:如果你需要分配大型的数组或对象,放在栈上可能会导致栈溢出,因此应该使用
new
在堆上分配。 -
变量大小的数组:如果数组的大小在编译时无法确定,则需要使用
new
在运行时分配所需内存。 -
对象的多态行为:如果你需要在运行时决定对象的确切类型(例如基于某种条件创建不同子类的实例),则需要使用指向基类的指针来分配具有多态行为的派生类实例。
-
对象生命周期管理:如果你想手动控制对象的生命周期,使用
new
和delete
能够让你精确控制对象何时被创建和销毁。
何时不使用new
:
-
自动存储期的对象:如果对象的使用限制在一个块的范围内,则不需要使用
new
。可以在栈上创建对象,它会在离开作用域时自动被销毁。 -
临时对象:对于只在函数内部使用的临时对象,直接在栈上创建即可,无需使用
new
。 -
异常安全性:在栈上创建对象通常更具异常安全性,如果异常发生,所有栈上的对象都会适时地被析构。
-
包含对象的区域:如果对象的全部或部分生命周期被另一个对象包含,通常可以在包含它的对象内部使用成员对象而不是指针。
-
智能指针:如果决定在堆上分配对象,应该考虑使用智能指针(如
std::unique_ptr
或std::shared_ptr
)来管理资源,它们会自动管理对象生命周期,避免忘记手动delete
。
在现代C++编程中,建议尽量避免裸new
和delete
,转而使用标准库容器(如std::vector
,std::string
)来管理资源,或使用智能指针来自动处理资源的释放。这样可以避免内存泄漏,简化程序,使程序更加健壮。
2.用delete释放内存,避免内存泄漏
3.C++的强制类型转换
4.面向对象程序设计思想有三大特征:封装、继承和多态。
5.类
6.权限控制符
7.在C++里,对于一个类的成员变量,如果在其中一个成员函数里被改变值了,那在调用另一个函数时,成员变量的值是什么?
在C++中,类的成员变量的值在不同成员函数之间是共享的。如果一个成员函数修改了类的成员变量的值,那么这个修改会影响该类的所有成员函数对该成员变量的访问。
举例说明:
#include <iostream>
class MyClass {
public:
int myValue;
void setValue(int value) {
myValue = value;
}
void printValue() {
std::cout << "myValue: " << myValue << std::endl;
}
};
int main() {
MyClass obj;
obj.myValue = 5;
obj.printValue(); // 输出: myValue: 5
obj.setValue(10);
obj.printValue(); // 输出: myValue: 10
return 0;
}
在上述示例中,MyClass
类有一个成员变量myValue
,并有两个成员函数setValue
和printValue
。在main
函数中,先设置obj
对象的myValue
为5,然后调用setValue
函数将其值设置为10,最后再次调用printValue
函数打印myValue
的值,结果会是10
,因为第一个函数修改了myValue
的值,而第二个函数访问的是修改后的值。
因此,在C++中,一个类的成员函数对其成员变量的修改是可见的,并影响其他成员函数对该成员变量的访问。
8.类的构造函数
C++中的每个类至少要有一个构造函数,如果类中没有定义构造函数,系统会提供一个默认的无参构造函数,默认的无参构造函数体也为空,不具有实际的初始化意义。
8.1 无参构造函数
1 #include<iostream>
2 #include<iomanip>
3 using namespace std;
4 class Clock //定义时钟类Clock
5 {
6 public:
7 Clock(); //声明无参构造函数
8 void showTime(); //声明显示时间的成员函数
9 private:
10 int _hour; //声明表示小时的成员变量
11 int _min; //声明表示分钟的成员变量
12 int _sec; //声明表示秒的成员变量
13 };
14 Clock::Clock() //类外实现无参构造函数
15 {
16 _hour=0; //初始化过程,将成员变量初始化为0
17 _min=0;
18 _sec=0;
19 }
20 void Clock::showTime() //类外实现成员函数
21 {
22 cout<<setw(2)<<setfill('0')<<_hour<<":"
23 <<setw(2)<<setfill('0')<<_min<<":"
24 <<setw(2)<<setfill('0')<<_sec<<endl;
25 }
26 int main()
27 {
28 Clock clock; //创建对象clock
29 cout<<"clock:";
30 clock.showTime(); //通过对象调用成员函数showTime()显示时间
31 return 0;
32 }
8.2 有参构造函数
1 #include<iostream>
2 #include<iomanip>
3 using namespace std;
4 class Clock //定义时钟类Clock
5 {
6 public:
7 Clock(int hour, int min, int sec); //声明有参构造函数
8 void showTime(); //用于显示时间的成员函数
9 private:
10 int _hour; //声明表示小时的成员变量
11 int _min; //声明表示分钟的成员变量
12 int _sec; //声明表示秒的成员变量
13 };
14 Clock::Clock(int hour, int min, int sec) //类外实现有参构造函数
15 {
16 _hour=hour; //初始化过程,将初始值直接赋值给成员变量
17 _min=min;
18 _sec=sec;
19 }
20 void Clock::showTime() //类外实现成员函数
21 {
22 cout<<setw(2)<<setfill('0')<<_hour<<":"
23 <<setw(2)<<setfill('0')<<_min<<":"
24 <<setw(2)<<setfill('0')<<_sec<<endl;
25 }
26 int main()
27 {
28 Clock clock1(10,20,30); //创建对象clock1,传入初始值
29 cout<<"clock1:";
30 clock1.showTime(); //通过对象调用成员函数showTime()显示时间
31 Clock clock2(22,16,12); //创建对象clock2,传入初始值
32 cout<<"clock2:";
33 clock2.showTime(); //通过对象调用成员函数showTime()显示时间
34 return 0;
35 }
9.含有成员对象的类的构造函数
1 #include<iostream>
2 using namespace std;
3 class Birth //定义出生日期类Birth
4 {
5 public:
6 Birth(int year,int month, int day); //构造函数
7 void show(); //声明成员函数show()显示日期
8 private:
9 int _year;
10 int _month;
11 int _day;
12 };
13 //类外实现构造函数
14 Birth::Birth(int year, int month, int day)
15 :_year(year),_month(month),_day(day)
16 {
17 cout<<"Birth类构造函数"<<endl;
18 }
19 //类外实现show()函数
20 void Birth::show()
21 {
22 cout<<"出生日期:"<<_year<<"-"<<_month<<"-"<<_day<<endl;
23 }
24 class Student //定义学生类Student
25 {
26 public:
27 //构造函数
28 Student(string name, int id, int year, int month, int day);
29 void show();
30 private:
31 string _name;
32 int _id;
33 Birth birth;
34 };
35 //类外实现构造函数
36 Student::Student(string name, int id, int year, int month, int day)
37 :birth(year,month,day)
38 {
39 cout<<"Student类构造函数"<<endl;
40 _name=name;
41 _id=id;
42 }
43 //类外实现show()函数
44 void Student::show()
45 {
46 cout<<"姓名:"<<_name<<endl;
47 cout<<"学号:"<<_id<<endl;
48 birth.show();
49 }
50 int main()
51 {
52 Student stu("lili",10002,2000,1,1); //创建学生对象stu
53 stu.show(); //显示学生信息
54 return 0;
55 }
10.析构函数(释放类的资源)
1 #define _CRT_SECURE_NO_WARNINGS
2 #include<iostream>
3 using namespace std;
4 class Rabbit //定义兔子类Rabbit
5 {
6 public:
7 Rabbit(string name,const char* pf); //声明构造函数
8 void eat();
9 ~Rabbit(); //声明析构函数
10 private:
11 string _name; //声明表示兔子名字的成员变量
12 char* _food; //声明表示兔子食物的成员变量
13 };
14 Rabbit::Rabbit(string name, const char* pf)
15 {
16 cout<<"调用构造函数"<<endl;
17 _name=name;
18 _food=new char[50]; //为_food指针申请空间
19 memset(_food,0,50); //初始化_food空间
20 strcpy(_food,pf); //将参数pf指向的数据复制到_food中
21 }
22 void Rabbit::eat()
23 { //类外实现成员函数
24 cout<<_name<<" is eating "<<_food<<endl;
25 }
26 Rabbit::~Rabbit() //类外实现析构函数
27 {
28 cout<<"调用析构函数,析构"<<_name<<endl;
29 if(_food != NULL)
30 delete []_food;
31 }
32 int main()
33 {
34 Rabbit A("A","luobo");
35 A.eat();
36 Rabbit B("B","baicai");
37 B.eat();
38 return 0;
39 }
10const常成员变量
11.const常成员函数
12.Static修饰成员变量和成员函数
1 #include<iostream>
2 using namespace std;
3 class Student //定义学生类Student
4 {
5 public:
6 Student(string name); //声明有参构造函数
7 ~Student(); //声明析构函数
8 static int _sum; //声明表示学生总数的静态成员变量
9 private:
10 string _name; //声明表示学生姓名的成员变量
11 };
12 //类外实现Student类有参构造函数
13 Student::Student(string name)
14 {
15 this->_name=name;
16 _sum++;
17 }
18 Student::~Student(){} //类外实现析构函数
19 int Student::_sum = 0; //类外初始化静态成员变量_sum
20 int main()
21 {
22 Student stu1("张三");
23 Student stu2("李四");
24 cout<<"人数是:"<<stu1._sum<<endl; //通过对象访问静态成员变量
25 cout<<"人数是:"<<stu2._sum<<endl;
26 cout<<"人数是"<<Student::_sum<<endl; //通过类访问静态成员变量
27 cout<<"stu1的大小是:"<<sizeof(stu1)<<endl;
28 return 0;
29 }
1 #include<iostream>
2 #include<math.h>
3 using namespace std;
4 class Point //定义坐标点类Point
5 {
6 public:
7 Point(float x,float y);
8 ~Point();
9 static float getLen(Point& p1,Point& p2); //声明静态成员函数
10 static float _len; //声明静态成员变量_len
11 private:
12 float _x;
13 float _y;
14 };
15 float Point::_len=0;
16 Point::Point(float x=0,float y=0):_x(x),_y(y) //类外实现有参构造函数
17 {
18 cout<<"初始化坐标点"<<endl;
19 }
20 Point::~Point(){}
21 float Point::getLen(Point &p1,Point &p2) //类外实现有参构造函数
22 {
23 float x=abs(p1._x-p2._x);
24 float y=abs(p1._y-p2._y);
25 _len=sqrtf(x*x+y*y);
26 return _len;
27 }
28 int main()
29 {
30 Point p1(1,2);
31 Point p2(6,8);
32 cout<<Point::getLen(p1,p2)<<endl;
33 return 0;
34 }
13.const和static不用在c++的类里去定义成员变量和成员函数,而是用在c里有什么作用?
在C语言中,const
和static
修饰符用于变量和函数,具有以下意义:
const
修饰符:
- 常量声明:通过使用
const
关键字修饰变量,可以将其声明为常量,即不可修改的值。这样可以在代码中定义常量,并且能够防止意外修改变量值,提高代码的可读性和可维护性。 - 编译时常量:使用
const
修饰的变量在编译时可以被当做常量进行优化,例如将其内联到代码中或进行常量折叠等。
示例:
const int MAX_VALUE = 100; // 声明一个常量
const float PI = 3.14; // 声明一个常量
int main() {
const int x = 5; // 声明并初始化一个常量
// x = 10; // 错误,常量不可修改
int array[MAX_VALUE]; // 使用常量作为数组大小
const int *ptr = &x; // 声明一个指向常量的指针
// *ptr = 7; // 错误,不可通过指针修改常量的值
return 0;
}
static
修饰符:
- 文件作用域:在全局变量和函数声明之前使用
static
关键字,可以将其作用域限制在当前文件中,避免与其他文件中的同名变量或函数产生冲突。 - 静态局部变量:在函数内部使用
static
关键字修饰局部变量,可以将其生命周期延长到整个程序的执行期间,并且在函数多次调用时保持其值不变。 - 静态函数:使用
static
关键字修饰函数,可以将其限制在当前文件中的可见性,只能在当前文件内部调用,无法被其他文件访问,起到了信息隐藏和封装的作用。
示例:
static int globalVar = 10; // 声明一个全局静态变量
void foo() {
static int count = 0; // 静态局部变量
count++;
printf("Count: %d\n", count);
}
static void bar() { // 声明一个静态函数
printf("This is a static function\n");
}
int main() {
foo(); // 输出 Count: 1
foo(); // 输出 Count: 2
bar(); // 函数可直接调用
return 0;
}
总的来说,const
和static
在C语言中的用法可以提供更好的代码控制和可读性,用于定义常量、限制变量的可修改性、将变量或函数的作用域限定在当前文件中等。它们是C语言中常用的修饰符。
14.普通函数、类成员函数作为“类的友元函数”
1 #include<iostream>
2 using namespace std;
3 class Circle
4 {
5 friend void getArea(Circle &circle); //声明普通函数getArea()为友元函数
6 private:
7 float _radius;
8 const float PI=3.14;
9 public:
10 Circle(float radius);
11 ~Circle();
12 };
13 Circle::Circle(float radius=0):_radius(radius)
14 {
15 cout<<"初始化圆的半径为:"<<_radius<<endl;
16 }
17 Circle::~Circle(){}
18 void getArea(Circle &circle)
19 {
20 //访问类中的成员变量
21 cout<<"圆的半径是:"<<circle._radius<<endl;
22 cout<<"圆的面积是"<<circle.PI*circle._radius*circle._radius<<endl;
23 cout<<"友元函数修改半径:"<<endl;
24 circle._radius=1;
25 cout<<"圆的半径是:"<<circle._radius<<endl;
26 }
27 int main()
28 {
29 Circle circle(10);
30 getArea(circle);
31 return 0;
32 }
1 #include<iostream>
2 #include<math.h>
3 using namespace std;
4 class Point;
5 class Circle
6 {
7 public:
8 float getArea(Point &p1,Point &p2); //声明计算面积的成员函数
9 private:
10 const float PI=3.14;
11 };
12 class Point
13 {
14 //声明类Circle的成员函数getArea()为友元函数
15 friend float Circle::getArea(Point &p1,Point &p2);
16 public:
17 Point(float x,float y);
18 ~Point();
19 private:
20 float _x;
21 float _y;
22 };
23 Point::Point(float x=0,float y=0):_x(x),_y(y) //实现Point类的构造函数
24 {
25 cout<<"初始化坐标点"<<endl;
26 }
27 Point::~Point(){}
28 float Circle::getArea(Point &p1,Point &p2)
29 {
30 double x=abs(p1._x-p2._x); //获取横轴坐标间的距离
31 float y=abs(p1._y-p2._y); //获取纵轴坐标间的距离
32 float len=sqrtf(x*x+y*y); //计算两个坐标点之间的距离
33 cout<<"获取两个坐标点之间的距离是"<<len<<endl;
34 return len*len*PI; //友元函数访问私有成员变量PI
35 }
36 int main()
37 {
38 Point p1(5,5);
39 Point p2(10,10);
40 Circle circle;
41 float area=circle.getArea(p1,p2);
42 cout<<"圆的面积是:"<<area<<endl;
43 return 0;
44 }
15 友元类
1 #include<iostream>
2 using namespace std;
3 class Time //定义Time类,描述时分秒
4 {
5 public:
6 Time(int hour, int minute, int second); //声明有参构造函数
7 friend class Date; //声明类Date为友元类
8 private:
9 int _hour, _minute, _second;
10 };
11 class Date //定义Date类
12 {
13 public:
14 Date(int year, int month, int day); //声明有参构造函数
15 void showTime(Time& time); //声明显示时间的成员函数
16 private:
17 int _year, _month, _day;
18 };
19 Date::Date(int year, int month, int day) //实现Date类构造函数
20 {
21 _year = year;
22 _month = month;
23 _day = day;
24 }
25 void Date::showTime(Time& time)
26 {
27 cout << _year << "-" << _month << "-" << _day
28 << " " << time._hour << ":" << time._minute
29 << ":" << time._second << endl;
30 }
31 Time::Time(int hour,int minute,int second) //实现Time类构造函数
32 {
33 _hour = hour;
34 _minute = minute;
35 _second = second;
36 }
37 int main()
38 {
39 Time time(17,30,20); //创建Time对象
40 Date date(2019,10,31); //创建Date对象
41 date.showTime(time); //调用showTime()显示年月日、时分秒信息
42 return 0;
43 }
16.运算符重载
1 #include<iostream>
2 using namespace std;
3 class A
4 {
5 private:
6 int _x;
7 int _y;
8 public:
9 A(int x=0,int y=0):_x(x),_y(y){}
10 void show() const; //输出数据
11 A operator+(const A& a) const; //重载"+"运算符
12 A operator-(const A& a) const; //重载"-"运算符
13 };
14 void A::show() const //show()函数的实现
15 {
16 cout<<"(_x,_y)="<<"("<<_x<<","<<_y<<")"<<endl;
17 }
18 A A::operator+(const A& a) const //重载"+"运算符的实现
19 {
20 return A(_x+a._x,_y+a._y);
21 }
22 A A::operator-(const A& a) const //重载"-"运算符的实现
23 {
24 return A(_x-a._x,_y-a._y);
25 }
26 int main()
27 {
28 A a1(1,2);
29 A a2(4,5);
30 A a;
31 cout<<"a1: ";
32 a1.show();
33 cout<<"a2: ";
34 a2.show();
35 a=a1+a2; //实现两个对象相加
36 cout<<"a: ";
37 a.show();
38 a=a1-a2; //实现两个对象相减
39 cout<<"a: ";
40 a.show();
41 return 0;
42 }
17.继承
1 #include<iostream>
2 using namespace std;
3 class Student //定义学生类Student
4 {
5 public:
6 void setGrade(string grade); //设置年级的成员函数
7 string getGrade(); //获取年级的成员函数
8 void setName(string name); //设置姓名的成员函数
9 string getName(); //获取姓名的成员函数
10 protected:
11 string _grade; //保护成员:表示年级
12 private:
13 string _name; //私有成员:表示姓名
14 };
15 void Student::setGrade(string grade) //类外实现setGrade()函数
16 {
17 _grade=grade;
18 }
19 string Student::getGrade() //类外实现getGrade()函数
20 {
21 return _grade;
22 }
23 void Student::setName(string name) //类外实现setName()函数
24 {
25 _name=name;
26 }
27 string Student::getName() //类外实现getName()函数
28 {
29 return _name;
30 }
31 class Undergraduate:public Student //大学生类公有继承学生类
32 {
33 public:
34 Undergraduate(string major); //声明构造函数
35 void show(); //声明显示大学生信息的成员函数
36 private:
37 string _major; //私有成员:表示专业
38 };
39 //类外实现构造函数
40 Undergraduate::Undergraduate(string major)
41 {
42 _major=major;
43 }
44 void Undergraduate::show() //类外实现show()函数
45 {
46 cout<<"姓名:"<<getName()<<endl; //派生类调用基类成员函数
47 cout<<"年级:"<<_grade<<endl; //派生类访问继承的基类成员变量
48 cout<<"专业:"<<_major<<endl; //派生类访问新增成员
49 }
50 int main()
51 {
52 //创建大学生类对象stu
53 Undergraduate stu("计算机信息工程");
54 stu.setGrade("大三"); //派生类对象调用基类成员函数设置年级
55 stu.setName("zhangsan"); //派生类对象调用基类成员函数设置姓名
56 stu.show(); //派生类对象调用新增成员函数显示学生信息
57 return 0;
58 }