C++ 类中的四个默认成员函数
-
构造函数
-
拷贝构造函数
-
析构函数
-
赋值运算符重载
class 类名{
public:
类名(void);
类名(const 类名 &);
~类名(void);
类名 & operator =(const 类名 &);
};
赋值运算符重载:
作用:代替默认的赋值运算符成员函数来控制对象复制的过程,从而避免复制过程中的浅拷贝。
调用时机: 在对象已经创建,并在后续运行阶段对其值进行修改时调用。
语法:
class 类名{
类名 & operator = (const 类名 & src) {
...
return *this;
}
};
示例:
#include <iostream>
#include <stdlib.h>
#include <string.h>
using namespace std;
// 定义一个MyString类,使用动态数组来存储字符信息
class MyString {
public:
// 将字符串初始化成 n个内容为 c的字符
MyString(char c, int n) {
cout << "MyString(" << c << "," << n<<")\n";
data = (char*)malloc(n+1);
for (int i = 0; i < n; i++) {
data[i] = c;
}
data[n] = '\0';
}
MyString(const char * p=""):data(NULL) {
cout << "MyString(" << p << ")\n";
// 计算传入参数的长度
int str_len = strlen(p);
data = (char*)malloc(str_len+1);
strcpy(data, p);
}
// 拷贝构造函数,对指针执向的内容进行深度复制
MyString(const MyString & src) {
cout << "MyString(const MyString& src.data:" << src.data << ")\n";
// 求源对象字符的长度
int str_len = strlen(src.data);
data = (char*) malloc(str_len+1);
strcpy(data, src.data);
}
// 析构函数
~MyString(){
cout << "~MyString(" << data << ")" << endl;
free(data);
}
MyString& operator=(const MyString &src) {
cout << "operator = 被调用" << endl;
// (*this).copy(src);
this->copy(src);
// 释放自己原有的内存
// free(data);
// int str_len = strlen(src.data);
// data = (char*)malloc(str_len+1);
// strcpy(data, src.data);
return *this;
}
const char * c_str(void) {
return data;
}
private:
char * data;
public:
// 要求不能有内存泄漏
void copy(const char * content) {
// 释放自己原有的内存
free(data);
int str_len = strlen(content);
data = (char*)malloc(str_len+1);
strcpy(data, content);
}
inline void copy(const MyString & src){
// 释放自己原有的内存
free(data);
int str_len = strlen(src.data);
data = (char*)malloc(str_len+1);
strcpy(data, src.data);
}
};
int main(int argc, char * argv[]) {
MyString s1 = "zhangsan";
MyString s2 = s1;
MyString s3;
// MyString s2;
// s2.copy(s1);
//调用MyString& MyString::operator=(const MyString&);
s3 = s2 = s1;
cout << "s1:" << s1.c_str() << endl; // zhangsan
cout << "s2:" << s2.c_str() << endl; // zhangsan
cout << "s3:" << s3.c_str() << endl; // zhangsan
s2.copy("lisi");
cout << "s2:" << s2.c_str() << endl; // lisi
cout << "程序结束!" << endl;
return 0;
}
构造函数调用的时机
- 栈、堆以及全局对象的对象创建。
- 函数参数传值(传引用和传址不会创建新对象)
- 函数返回值(非引用和传址是不会创建新对象)
示例:
#include <iostream>
#include <stdlib.h>
#include <string.h>
using namespace std;
class MyString2 {
public:
MyString2(const string & s="") {
cout << "MyString2(" << s << ")" << endl;
data = s;
}
// 拷贝构造函数,对指针执向的内容进行深度复制
MyString2(const MyString2 & src) {
cout << "拷贝构造MyString2()" << src.data << endl;
data = src.data;
}
// 析构函数
~MyString2(){
cout <<"~MyString2(" << data << ")" << endl;
}
MyString2& operator=(const MyString2 &src) {
cout << "operator = 被调用:"<< data << endl;
data = src.data;
return *this;
}
private:
string data;
};
MyString2 &myfun(MyString2 & arg1) {
return arg1;
}
int main(int argc, char * argv[]) {
MyString2 s1("A1");
// MyString2 s2;
MyString2 &s2 = myfun(s1);
cout << "程序结束!" << endl;
return 0;
}
类的声明方式
- 仅声明类
- 声明类,同时声明成员变量和成员函数.
仅声明类
class 类名;
声明类,同时声明成员变量和成员函数。
class 类名 {
public:
类名(形式参数列表);
返回类型 成员函数名(形式参数列表);
...
private:
变量类型1 成员变量1;
变量类型2 成员变量2;
...
};
友元声明
友元声明是指让声明的一个函数、类或成员函数可以访问该类的私有和保护成员。
作用:让全局函数、其他类或其他类的成员函数可以访问该类的私有和保护成员。
关键字 friend
友元声明的分类
- 友元函数
- 友元成员函数
- 友元类
语法:
class 类名 {
// 友元函数的声明语法
friend 返回类型 友元函数名(形式参数列表);
// 友元成员函数的声明语法
friend 返回类型 其他类::类名友元函数名(形式参数列表);
// 友元类的声明语法
friend class 其他类;
};
示例代码
#include <iostream>
using namespace std;
class Children; // 类声明
class Parent{
public:
Parent(const string & n, int a)
: name(n),age(a),money(0){}
void work(int m);
void showInfo(void);
void giveMoneyTo(Children & c, int m); // 给孩子钱
private:
string name;
int age;
int money;
// 声明show_money函数可以访问本类的所有成员
friend void show_money(const Parent &);
friend class Children;
};
class Children {
public:
Children(const string & n, int a)
: name(n),age(a),money(0){}
void showInfo(void);
void borrowTo(Parent & p, int m);
private:
string name;
int age;
int money;
// 仅声明Parent类的giveMoneyTo函数可以访问本类的所有成员
friend void Parent::giveMoneyTo(Children & c, int m);
};
void Parent::work(int m) {
money += m;
}
void Parent::showInfo(void) {
cout << age << "岁的" << name << "有钱" << money
<< "元" << endl;
}
void Children::showInfo(void) {
cout << age << "岁的" << name << "有钱" << money
<< "元" << endl;
}
void Parent::giveMoneyTo(Children & c, int m) {
if (m > this->money) {
cout << "钱不够" << endl;
return;
}
this->money -= m;
c.money += m;
}
void Children::borrowTo(Parent & p, int m) {
if (m > this->money) {
cout << "本宝宝没钱,不借" << endl;
return;
}
this->money -= m;
p.money += m;
}
// 全局函数,用来打印家长的钱数;
void show_money(const Parent & p) {
cout << p.age << "岁的" << p.name << "有钱"
<< p.money << "元" << endl;
}
int main(int argc, char * argv[]) {
Parent p("老张", 31);
Children c("小张", 12);
p.work(1000);
show_money(p);
p.giveMoneyTo(c, 700);
p.showInfo();
c.showInfo();
c.borrowTo(p, 200);
p.showInfo();
c.showInfo();
return 0;
}
常成员函数
作用:声明一个成员函数为常成员函数,常成员函数在修改该类成员变量时将会报错(在编译阶段报错),且不能调用非 常成员函数
。
语法:
class 类名{
返回类型 成员函数名(形式参数列表) const {...}
};
示例代码
#include <iostream>
using namespace std;
class Parent{
public:
Parent(const string & n, int a)
: name(n),age(a),money(0){}
void work(int m);
void showInfo(void) const;
private:
string name;
int age;
int money;
};
void Parent::work(int m) {
money += m;
}
void Parent::showInfo(void) const {
cout << age << "岁的" << name << "有钱" << money
<< "元" << endl;
// money = 0; // 报错
// this->work(100); // 报错
}
int main(int argc, char * argv[]) {
Parent p("老张", 31);
p.work(1000);
p.showInfo();
return 0;
}
静态成员函数和静态成员变量
静态成员变量
是类内的变量,他的作用域属于类。
声明的语法:
class 类名{
访问说明符:
static 变量类型 变量名;
};
初始化的语法
变量类型 类名::变量名[ = 初始值];
静态成员变量的使用方法
类名::变量名
对象名.变量名
示例:
记录一个类创建对象的个数;
#include <iostream>
#include <stdlib.h>
#include <string.h>
using namespace std;
class Human {
public:
static int total_count;
Human(const string & n) : name(n){
cout << "Human(" << name << ")\n";
total_count++;
}
~Human(){
cout << "~Human(" << name << ")\n";
total_count--;
}
private:
string name;
};
int Human::total_count = 0;
int main(int argc, char * argv[]) {
Human zhang3("张三");
do {
Human li3("李四");
} while(0);
// 程序运行到此处能否指导此时创建了几个Human对象?
cout << "人口总数" << Human::total_count << endl;
cout << "人口总数" << zhang3.total_count << endl;
cout << "程序结束!" << endl;
return 0;
}
静态成员函数
是类的函数,他只能访问类的静态成员变量,不能访问对象的成员变量。
说明:
- 静态成员函数 没有this指针,不能访问对象的成员变量。
- 静态成员函数的作用域属于据类。
静态成员函数 的定于的语法
class 类名{
public:
// 类内声明,类内实现。
static 返回类型 函数名1(形式参数列表) {};
// 类内声明,类外实现。
static 返回类型 函数名2(形式参数列表);
}
类外实现的语法
返回类型 类名::函数名2(形式参数列表) { ... }
调用方法
类名::函数名2(实际参数列表)
对象.函数名2(实际参数列表)
面相对象编程语言的特征
- 封装
- 继承
- 多态
封装
封装是指隐藏对象的实现细节,让使用者不关心这些细节。从而保证数据的安全性。
使用者只需要调用简单的接口的即可使用。
C++ 通过访问说明符实现封装。
访问说明符
public
protected
private
访问说明符 | 成员函数 | 子类成员函数 | 其他 |
---|---|---|---|
public | 可以访问 | 可以访问 | 可以访问 |
protected | 可以访问 | 可以访问 | 无法访问 |
private | 可以访问 | 无法访问 | 无法访问 |
继承
继承是允许一个类(子类或派生类)基于另外一个类(父类或基类)创建,并继承基类的成员变量和成员函数。
继承的作用:
- 将公有部分放入基类,实现代码共享。
- 子类可以在原有的基础上添加新的功能。
继承的语法:
class 子类名:继承方式 基类名 {
...
};
继承方式
- 共有继承 public
- 保护继承 protected
- 私有继承 private
继承的内存结构

显式调用父类的构造函数的语法
class 子类名:继承方式 基类名 {
public:
子类名(形参列表): 基类名(实参),成员变量1(实参),成员变量2(实参){...}
};
示例:
#include <iostream>
#include <stdlib.h>
#include <string.h>
using namespace std;
// 点类(描述一个点的位置,面积,周长等信息
class Point {
public:
Point(int ax=0, int ay=0):x(ax), y(ay) {
cout << "Point(" << x << "," << y << ")\n";
}
void info(void) {
cout << "点(" << x << "," << y << ")\n";
}
void moveTo(int new_x, int new_y) {
x = new_x; y = new_y;
}
float getArea(void) {
return 0;
}
float getLength(void) {
return 0;
}
public:
int x;
int y;
};
// 定义一个圆的类(位置和半径)
class Circle : public Point {
public:
Circle(int ax, int ay, int radius)
: Point(ax, ay), r(radius) {
// x = ax; y = ay; r = radius;
cout << "Circle(" << x << "," << y << "," << r << ")\n";
}
// void info(void) {
// cout << "圆(" << x << "," << y << "," << r << ")\n";
// }
// float getArea(void) {
// return 0;
// }
// float getLength(void) {
// return 0;
// }
public:
int r; // 半径
};
int main(int argc, char * argv[]) {
Point p1(3, 5);
Circle c1(4, 6, 10);
cout << "sizeof(p1)" << sizeof(p1) << endl;
cout << "sizeof(c1)" << sizeof(c1) << endl;
c1.info();
p1.info();
p1.moveTo(100, 105);
// 子类对象不存在moveTo,则调用父类的方法
c1.moveTo(200, 210);
p1.info();
c1.info();
cout << "程序结束!" << endl;
return 0;
}
访问权限
基类访问权限 | 继承方式 | 本类访问权限 |
---|---|---|
public | public | public |
protected | public | protected |
private | public | 不可访问 |
public | protected | protected |
protected | protected | protected |
private | protected | 不可访问 |
public | private | private |
protected | private | private |
private | private | 不可访问 |