封装
类的基本思想:数据抽象和封装
数据抽象是一种依赖接口和实现分离的编程技术
接口:类的用户所能执行的操作
实现:类的数据成员、接口函数的实现及其他私有函数的实现
封装:实现了类的接口和实现分离
封装后的类隐藏了实现细节;
类的用户只能使用接口而无法访问实现部分。
面向对象三大特性:封装、继承、多态
访问控制
struct结构体→结构体变量
class类→对象
- 数据与行为不分离(成员变量,成员函数)
- 权限控制:
类内开放,类外控制
保证数据的完整、正确性 - 成员函数,调用内部变量不需要传参
访问说明符:
public:公共的
protected:保护的
private:私有的
C++中class和struct没有本质区别,只是默认权不同。
C语言版
///c格式,struct
#include <stdio.h>
typedef struct _Date {
int y, m, d;
}Date;
int isValid(Date *pd) {
if (pd->y > 0 && pd->y < 9999 &&
pd->m >0 && pd->m < 13 &&
pd->d>0 && pd->d < 32)
return 1;
return 0;
}
void init(Date *pd) {
while (1) {
printf("请输入年 月 日:\n");
scanf("%d%d%d", &pd->y, &pd->m, &pd->d);
if (isValid(pd)) break;
printf("输入格式错误,重新输入!\n");
}
}
void print(Date *pd) {
printf("%d-%d-%d\n", pd->y, pd->m, pd->d);
}
int main()
{
Date d1;
init(&d1);
print(&d1);
return 0;
}
C语言的问题:结构体中所有东西都是可见和操作的
C++版
#include <iostream>
using namespace std;
class Date {
public:
void init() {
while (1) {
cout << "请输入年 月 日:" << endl;
cin >> y >> m >> d;
if (isValid()) break;
cout << "输入错误,重新输入!" << endl;
}
}
void print() {
cout << y << "-" << m << "-" << d << endl;
}
private:
bool isValid() {
if (y > 0 && y < 9999 && m>0 &&
m < 13 && d>0 && d < 32)
return true;
return false;
}
int y, m, d;
};
int main() {
Date d1;
d1.init();
d1.print();
return 0;
}
栈类
#include <iostream>
using namespace std;
class Stack {
public:
bool isEmpty()const { return topidx == 0; }
bool isFull()const { return topidx == size; }
void init(int len = 1024) {
ps = new int[len];
size = len;
topidx = 0;
}
void destroy() {
if (ps) delete[] ps;
ps = NULL;
}
int top()const {
return ps[topidx - 1];
}
void push(int data) {
ps[topidx++] = data;
}
void pop() {
topidx--;
}
private:
int *ps;
int topidx;
int size;
};
int main() {
Stack S;
S.init();
for (int i = 0; i < 5; i++) {
if (!S.isFull())
S.push(i);
}
while (!S.isEmpty()) {
cout << S.top() << " ";
S.pop();
}
//S.topidx = 10; //错误,无法修改
S.destroy();
return 0;
}
构造函数与析构函数
构造函数:每个类都定义了它的对象被初始化的方式,类通过一个或多个特殊的成员函数来控制其对象的初始化。(生成对象时自动调用)
析构函数:释放对象使用的资源。(对象销毁时自动调用)
构造函数:与类名相同,无返回,可以有参数
析构函数:~与类名相同,无参数,无返回
#include <iostream>
using namespace std;
class Stack {
public:
Stack(int len = 1024) {
ps = new int[len];
size = len;
topidx = 0;
cout << "构造函数run..." << endl;
}
~Stack() {
if (ps) delete[] ps;
ps = NULL;
cout << "析构函数run..." << endl;
}
bool isEmpty()const { return topidx == 0; }
bool isFull()const { return topidx == size; }
int top()const {
return ps[topidx - 1];
}
void push(int data) {
ps[topidx++] = data;
}
void pop() {
topidx--;
}
private:
int *ps;
int topidx;
int size;
};
int main() {
Stack S;
//S.init(); //不再需要,被构造函数替代了
for (int i = 0; i < 5; i++) {
if (!S.isFull())
S.push(i);
}
while (!S.isEmpty()) {
cout << S.top() << " ";
S.pop();
}
cout << endl;
//S.destroy(); //不再需要,被析构函数替代了
return 0;
}
构造函数初步
- 可以有参数,有默认参数,可以重载
- 若未提供构造参数,系统默认生成一个无参空构造函数;若提供,则不再默认生成无参空构造函数
类名a; //调用无参构造函数[不能写成类名a(),编译器会认为是函数声明]
类名a();//调用有参构造函数,a{xx}也可以
通过new在堆空间创建对象,同样会自动调用构造函数
#include <iostream>
using namespace std;
class Stack {
public:
Stack() { //无参构造函数
ps = new int[1024];
size = 1024;
topidx = 0;
cout << "Stack() run" << endl;
}
Stack(int len) { //带参构造函数
ps = new int[len];
size = len;
topidx = 0;
cout << "Stack(int len) run" << endl;
}
/*Stack(int len = 1024) {
ps = new int[len];
size = len;
topidx = 0;
}*/
~Stack() {
if (ps) delete[] ps;
ps = NULL;
cout << "析构函数run..." << endl;
}
bool isEmpty()const { return topidx == 0; }
bool isFull()const { return topidx == size; }
int top()const {
return ps[topidx - 1];
}
void push(int data) {
ps[topidx++] = data;
}
void pop() {
topidx--;
}
private:
int *ps;
int topidx;
int size;
};
int main() {
Stack S1; //调用无参构造 不能写 Stack S1();
Stack S2(100); //调用带参构造
Stack S3{ 10 };//调用带参构造
Stack *p1 = new Stack; //无参构造
Stack *p2 = new Stack(10);//带参构造
Stack *p3 = new Stack{ 10 };//带参构造
//对照:
int a1; //不能写 int a1(); 这是函数声明
int a2(10);
int a3{ 10 };
int *pa1 = new int;
int *pa2 = new int(10);
int *pa3 = new int{ 20 };
return 0;
}
mystring类的构造函数
模范标准库的string类:
string s1; // 无参构造函数
string s2("abc");//有参构造函数
#include<iostream>
#include<string>
#include<string.h>
using namespace std;
class mystring{
public:
mystring(){
ps = new char[1];
ps[0] = '\0';
}
mystring(const char *str){
int len = strlen(str) + 1;
ps = new char[len];
strcpy(ps,str);
}
/*
myString(const char *str = NULL) {
if (str == NULL) {
ps = new char[1];
ps[0] = '\0';
}
else {
int len = strlen(str) + 1;
ps = new char[len];
strcpy(ps, str);
}
}*/
~mystring(){
delete[] ps;
}
const char* c_str() const{
return ps;
}
private:
char *ps;
};
int main(){
string s1;
string s2("abc");
cout<<"-"<<s1.c_str()<<"-"<<endl;
cout<<s2.c_str()<<endl;
mystring ms1;
mystring ms2("abc");
cout<<"-"<<ms1.c_str()<<"-"<<endl;
cout<<ms2.c_str()<<endl;
}
析构函数初步
析构函数:释放对象使用的资源(对象销毁时自动调用)
1.无参,无返回(不可重载)
2.若为提供,系统默认生成一个空的析构函数
通过delete销毁堆空间上的对象,同样会自动调用析构。
设计原则:自己申请的资源,自己负责释放
///析构函数初步 c代码
struct Stu {
char *name;
int age;
};
int main() {
//申请st1的内存
struct Stu *st1 =
(struct Stu*)malloc(sizeof(struct Stu));
//申请st1中name的内存
st1->name = (char*)malloc(sizeof(char)*20);
//释放st1中name的内存
free(st1->name);
//释放st1本身的内存
free(st1);
return 0;
}
C代码要逐级分别释放各自申请的资源
///C++代码
class Stu {
public:
Stu() {
name = new char[20];
age = 10;
}
~Stu() {
if (name) delete[] name;
}
private:
char *name;
int age;
};
int main() {
//申请st1的内存
Stu *st1 = new Stu;
delete st1;
return 0;
}
构造与析构的次序
1.多个对象,按次序构造,析构次序相反
2.类中有成员变量也是类对象的时候,先运行成员类的构造函数,在运行本类的构造函数。析构次序与构造次序相反。
3.注意类中成员变量是类的指针类型的话,不会调用构造函数
#include <iostream>
#include <stdio.h>
using namespace std;
class A {
public:
A(int i = 0) {
num = i;
cout << "A()" << num << endl;
}
~A() { cout << "~A()" << num << endl; }
private:
int num;
};
class B {
public:
B() { cout << "B()" << endl; }
~B() { cout << "~B()" << endl; }
};
int main() {
A a1;
A a2(1);
B b;
A *pa = new A[2]{ 2,3 }; //连续构造2次
delete[] pa; //连续析构2次
return 0;
}
#include <iostream>
#include <string>
#include <string.h>
using namespace std;
class myString {
public:
myString(const char *str = NULL) {
if (str == NULL) {
ps = new char[1];
ps[0] = '\0';
}
else {
int len = strlen(str) + 1;
ps = new char[len];
strcpy(ps, str);
}
cout << "myString构造" << endl;
}
~myString() {
if (ps) delete[] ps;
cout << "myString析构" << endl;
}
private:
char *ps;
};
class Stu {
public:
Stu() { cout << "Stu构造" << endl; }
~Stu() { cout << "Stu析构" << endl; }
private:
myString name;
int age;
};
int main() {
Stu st1;
return 0;
}
#include <iostream>
using namespace std;
class A {
public:
A() { cout << "A()" << endl; }
~A() { cout << "~A()" << endl; }
};
void fun() { A a2; }
int main() {
{
A a1;
}
//到这里,a1已经析构了。
fun();
//到这里,fun中的a2已经析构了。
cout << "----------" << endl;
int i = 0;
//注意a3的作用域
for (A a3; i < 3; i++) {
cout << i << endl;
}
cout << "----------" << endl;
//注意a4的作用域
for (int j = 0; j < 3; j++) {
A a4; //每次循环都会构造
cout << j << endl;
}//while循环也是如此
cout << "----------" << endl;
A *pa = new A; //构造
delete pa; //调用delete析构
return 0;
}
- 栈空间中的对象脱离作用域时,析构
- 堆空间中的对象delete时,析构
类文件写法
通常将一个类分为2个文件:类的声明写在类名.h;类的实现写在类名.cpp
一个类就是一个作用域
在类的外部定义成员函数时,返回值类型 类名::函数名(参数)
///myString.h
#ifndef MYSTRING_H
#define MYSTRING_H
#include <iostream>
class myString {
public:
myString(const char *str = NULL);
~myString();
const char* c_str()const;
private:
char *ps;
};
#endif // !MYSTRING_H
///调用
#include <iostream>
#include "myString.h"
using namespace std;
int main() {
myString s1;
return 0;
}
///myString.cpp
#include <string.h>
#include "myString.h"
//注意,默认参数要写在函数声明中
myString::myString(const char *str) {
if (str == NULL) {
ps = new char[1];
ps[0] = '\0';
}
else {
int len = strlen(str) + 1;
ps = new char[len];
strcpy(ps, str);
}
}
myString::~myString() {
delete[] ps;
}
const char* myString::c_str()const {
return ps;
}
对象的内存
类→对象,模具→产品
创建对象时:只有成员变量开辟内存,没有成员变量是,占用一个字节。成员函数并不占用对象的空间。
class 中的成员变量和C中的struct一样,要对齐、补齐。
#include <iostream>
using namespace std;
class A1 {};
class A2 { void fun() {} };
class A3 { int num; void fun() {} };
class A4 { int num; char name[6]; };
int main() {
cout << sizeof(A1) << endl; //1
cout << sizeof(A2) << endl; //1
cout << sizeof(A3) << endl; //4
cout << sizeof(A4) << endl; //12
return 0;
}
#include <iostream>
#include <string.h>
using namespace std;
class myString {
public:
myString(const char *str = NULL);
~myString();
private:
char *ps; int size;
};
myString::myString(const char *str) {
if (str == NULL) {
ps = new char[1];
ps[0] = '\0';
}
else {
int len = strlen(str) + 1;
ps = new char[len];
strcpy(ps, str);
}
}
myString::~myString() {
delete[] ps;
cout << "~myString()" << endl;
}
class Person {
public:
Person() { age = 20; p_fm = NULL; }
void set_fm(){
p_fm = new myString[2];
}
~Person() {
cout << "~Person()" << endl;
delete[] p_fm;
cout << "=========" << endl;
}
private:
int age; //年龄
myString name; //自己的名字
myString *p_fm; //父母的名字
};
int main() {
Person p1;
p1.set_fm();
return 0;
}
在内存怎么存储:
person P1 在栈里面:
this 指针
This 指针可以认为是顶层const,不能修改
为了区分num,对于外层的num用A::num表示,当然也可以用this->num
#include <iostream>
#include <string.h>
using namespace std;
class A {
public:
A(int num) { A::num = num; }
A(double num) { this->num = num; }
int num;
};
int main() {
A a1(20);
cout << a1.num << endl; //20
A a2(1.2);
cout << a2.num << endl; //1
return 0;
}
对象的内存和函数没有关系,怎么区分是哪一个num?
show函数是如何知道返回的是a1还是a2的num?
可想像为:int A::show( A* const this);
调用a1.show(&a1); a2.show(&a2);
成员函数隐式地传递了一个当前对象的指针参数
this指针:指向的是本对象的地址
#include <iostream>
#include <string.h>
using namespace std;
class A {
public:
A(int num) { this->num = num; }
int show()const { return num; }
private:
int num;
};
int main() {
A a1(20);
cout << a1.show() << endl; //20
A a2(1);
cout << a2.show() << endl; //1
return 0;
}
构造函数初始值列表
有些类中,初始化和赋值的区别事关低层效率的问题,初始化的先后顺序和成员变量出现的先后次序一致
#include <iostream>
#include <string.h>
using namespace std;
class A {
public:
A(int n, double f) { num = n; fd = f; }
private:
int num;
double fd;
};
class B {
public:
//构造函数的初始值列表
B(int n, double f) :num(n), fd(f) {}
private:
int num;
double fd;
};
int main() {
A a(10, 1.2);
B b(10, 1.2);
return 0;
}
A类在创建对象时,先分别对num和fd调用默认初始化;
然后再通过赋值语句给num和fd赋值。
B类在创建对象时,直接初始化num和fd.
A的流程:int num ; num = 10 ;
B的流程: int num(10);
假如是类成员变量:A--> myString ma; ms = "abc";
B--> myString ms("abc");
#include <iostream>
#include <string.h>
using namespace std;
class B {
public:
B(double f) :fd(f), num(fd) {}
int get_num()const { return num; }
private:
int num;
double fd;
};
int main() {
B b(1.2);
cout << b.get_num() << endl;
//没有得到预期中的 1
return 0;
}
初始值列表对成员变量的初始化先后次序,与成员变量在类中出现的先后次序一致。
尝试用排序靠后的成员变量来初始化前面的成员变量,会得到未知的结果。
拷贝构造和赋值运算符重载
拷贝构造函数:
class 类名{
类名(const 类名 & another);
}
- 系统提供默认的拷贝构造,若自己提供,则不复存在。
- 默认拷贝构造是等位拷贝,也就是所谓的浅拷贝。
- 要实现深拷贝,必须要自己实现
赋值运算符重载:
类名{
类名& operator = (const 类名 & 源对象)
....;
return *this;
}与拷贝构造类似
string s1("abc"); // 直接初始化
string s2("1234");
string s3(s2); // 直接初始化
string s4 = s2; // 拷贝初始化
string s5;
s5 = s2; // 赋值操作
默认的拷贝构造(浅拷贝)
class A {
public:
A(int n = 0) : num(n){}
A(const A &other) :num(other.num){}
private:
int num;
}
int main(){
A a1;
A a2(a1); //直接初始化
A a3 = a1; // 拷贝初始化
const A a4;
A a5 = a4; //参数没有const,就错误
return 0;
}
运算符重载
#include <iostream>
#include <string>
using namespace std;
class A {
public:
A(int n = 0) :num(n) {}
A(const A &other) :num(other.num){ }
A& operator=(const A &other) {
num = other.num;
return *this;
}
private:
int num;
};
int main() {
A a1;
A a2;
a2 = a1; //赋值
return 0;
}
浅拷贝
浅拷贝可能会造成内存泄漏、重析构
myString(const char * str = NULL){
ps = new char[len];
}
~myString(){
if(ps)
delete[] ps;
}
拷贝构造:myString s2 = s1;
等位拷贝:s1的ps指针赋给s2的ps
s1.ps 和 s2.ps同时指向同一个内存
s1,s2分别析构时,会两次释放同一内存
赋值运算符重载:
myString s1('AB')
myString s2('CD')
s2 = s1;
存在内存泄漏和重析构
深拷贝实现
class myString{
public:
myString(const char *str = NULL){
if(str == NULL){
ps = new char[1];
ps[0] = '\0';
}
else{
int len = strlen(str) +1;
ps = new char[len];
strcpy(ps,str);
}
}
}
myString(cosnt myString &other)'
myString& operator= (const myString & other);
~myString(){
delete[] ps;
}
private:
char *ps
拷贝构造
myString :: myString(const myString &other){
ps = new char[srelen(other.ps) +1];
strcpy(ps,other.ps);//拷贝构造
}
赋值运算符重载
myString & myString::operator = (const myString &other){
if(this == &other)//排除自己给自己赋值出错
return *this;
delete[] ps;
ps = new char[strlen(other.ps) + 1];
strcpy(ps, other.ps);
return *this;
}
友元
封装:类的数据成员定义为私有成员,外部要访问类的私有成员只能通过接口(如,get和set方法)
特殊情况:类外有些函数需要频繁的访问类的数据成员,此时可以将这些函数定义为该类的友元函数。友元的好处:提高了程序的运行效率(减少类型和安全检查及调用的时间开销)
友元的副作用:破坏了类的封装性和隐藏性,使得非成员函数可以直接访问类的私有成员。
友元
类的接口实现功能:
#include <iostream>
using namespace std;
class Person {
public:
void set_m_p_piece(int m) {
if (m >= 10.0 && m <= 100.0)
m_p_piece = m;
else
m_p_piece = 10.0;
}
double get_m_p_piece()const {
return m_p_piece;
}
void set_t_piece(int t) {
if (t <= 0) t_piece = 0;
else t_piece = t;
}
int get_t_piece()const {
return t_piece;
}
private:
double m_p_piece; //单件工资
int t_piece; //总件数
};
void set_Person(Person& person, double m, int t) {
person.set_m_p_piece(m);
person.set_t_piece(t);
}
double calc_Person(const Person& person) {
return
person.get_m_p_piece()*person.get_t_piece();
}
int main() {
Person person1;
for (int i = 0; i < 100000; i++) {
set_Person(person1, i, i);
cout << calc_Person(person1) << endl;
}
return 0;
}
友元函数:
#include <iostream>
using namespace std;
class Person {
public:
friend void set_Person(Person& person, double m, int t);
friend double calc_Person(const Person& person);
void set_m_p_piece(int m) {
if (m >= 10.0 && m <= 100.0)
m_p_piece = m;
else m_p_piece = 10.0;
}
double get_m_p_piece()const { return m_p_piece; }
void set_t_piece(int t) {
if (t <= 0) t_piece = 0;
else t_piece = t;
}
int get_t_piece()const { return t_piece; }
private:
double m_p_piece; //单件工资
int t_piece; //总件数
};
void set_Person(Person& person, double m, int t) {
person.m_p_piece = m;
person.t_piece = t;
}
double calc_Person(const Person& person) {
return person.m_p_piece * person.t_piece;
}
int main() {
Person person1;
for (int i = 0; i < 100000; i++) {
set_Person(person1, i, i);
cout << calc_Person(person1) << endl;
}
return 0;
}
前向声明
#include <iostream>
#include <cmath>
using namespace std;
class Point; //前向声明
class ManagerPoint{ //管理Point的类
public:
double distance(Point &a, Point &b);
};
class Point{ //Point类
public:
friend double ManagerPoint::distance(const Point &a, const Point &b);
Point(double x, double y):x(x),y(y) { }
void print()const;
const double &get_x()const { return x; }
const double &get_y()const { return y; }
private:
double x, y;
};
void Point::print()const {
cout << "(" << x << "," << y << ")" << endl;
}
double ManagerPoint::distance(const Point &a,const Point &b) {
double dx = a.x - b.x;
double dy = a.y - b.y;
return sqrt(dx*dx + dy*dy);
}
int main(){
Point p1(1.0, 1.0), p2(4.0, 5.0);
p1.print();
p2.print();
ManagerPoint mp;
double d = mp.distance(p1, p2);
cout << "Distance = " << d << endl;
return 0;
}
前向声明:是一种不完全声明
- 不能定义类的对象
2.可以用于定义指向这个类类型的指针或引用 - 用于声明,使用该类类型作为形参类型或者返回值类型
友元
- 友元关系不能被继承
- 友元关系是单向的,不具有交换性。若B是A的友元,A不一定是B的友元
- 友元关系不具有传递性。
若B是A的友元(B可以访问A的私有成员)
C是B的友元(C可以访问B的私有成员)
不等于C是A的友元
#include <iostream>
using namespace std;
class Point {
public:
friend class Stack; //友元类
Point(double x = 0.0, double y = 0.0)
:x(x), y(y) {}
private:
double x, y;
};
class Stack {
public:
Stack(int len = 1024);
~Stack();
bool isEmpty()const;
bool isFull()const;
const Point &top()const;
void push(const Point& data) {
ps[topidx++] = data;
cout << "(" << data.x << ","
<< data.y << ")" << endl;
}
void pop();
private:
Point *ps;
int topidx;
int size;
};
inline bool Stack::isFull()const {
return topidx == size;
}
Stack::Stack(int len) : topidx(0),
size(len) {
ps = new Point[len];
}
Stack::~Stack() {
delete[] ps;
ps = NULL;
}
bool Stack::isEmpty()const {
return topidx == 0;
}
const Point& Stack::top()const {
return ps[topidx - 1];
}
void Stack::push(const Point &data) {
ps[topidx++] = data;
cout << "(" << data.x << "," << data.y << ")" << endl;
}
void Stack::pop() {
topidx--;
}
int main(){
Point p1(1, 1);
Stack S;
S.push(p1);
return 0;
}
类的const常量成员
const成员变量,不能修改,只能在初始值列表中初始化
class A{
public :
A(int i = 0) : ci(i){}
//const 成员变量,只能通过初始值列表初始化
// A(int i = 0){ci = i;}//错误!
// void set_ci(int i ){ci = i;}//错误
private:
const int ci ;
}
const 成员函数:
- const放在函数声明之后,实现体之前 void fun() const{}
- 承诺在本函数内部不会修改类内的数据成员,不会调用其它非const成员函数
- const 构成函数重载(why?this指针底层const)
#include <iostream>
using namespace std;
class A {
public:
A(int i = 0) :ci(i),num(i) { }
int get_ci()const {
return ci;
}
void show()const {
//set_num(0); //错误,调用非const函数
//num = 0; //错误,修改数据成员
cout << num*ci << endl; //正确,调用不修改
get_ci(); //正确,调用const函数
cout << "show() const" << endl;
}
void show() { //重载
cout << "show()" << endl;
}
int set_num(int i) { num = i; }
private:
const int ci;
int num;
};
int main(){
A a; //普通对象
const A ca; //const对象
//ca.set_num(100); //错误,const对象只能调用const函数
ca.show(); // show() const
a.show(); //show() 非const [非const对象也可调用const函数]
return 0;
}
类的static静态成员
static成员变量:同类对象间信息共享类外存储,必须类外初始化,可通过类名访问,也可通过对象访问。
静态成员函数:管理静态数据成员,对静态数据成员封装(对外提供接口) (可以认为和全局函数相似)
静态成员函数:只能访问静态数据成员。静态成员函数属于类,没有this指针
#include <iostream>
using namespace std;
class Person {
public:
Person(int _age) :age(_age) { sum += _age; count++; }
static int get_count();
static double get_avg() { return double(sum) / count; }
private:
int age; //年龄
static int count;//总人数
public:
//不能 static int sum=0;
static int sum; //年龄总和
};
//此处不能加 static
int Person::get_count() { return count; }
//此处不能加 static
int Person::sum = 0; //必须初始化
int Person::count = 0; //数据区(bss,rw?)
int main(){
//外部直接访问方式,类名::静态变量名
cout << Person::sum << endl;
//cout << Person::count; //错误,同样有权限控制
//静态成员变量不占用对象的内存空间
cout << sizeof(Person) << endl; //4
Person p1(10);
//静态变量,也可以通过 对象.变量名 来访问
//类外需要权限,类内部都行
cout << p1.sum << endl;
Person p2(20);
//静态成员函数,可以通过 类名::函数名 来访问
cout << Person::get_avg() << endl;
//也可以通过 对象.函数名 来访问
cout << p1.get_count() << endl; //2
cout << p2.get_count() << endl; //与上面输出一致
return 0;
}
单例模式
- 将默认的构造函数和析构函数声明为私有,外部无法创建,无法销毁(只能自己销毁自己)
- 使用一个私有的静态本类类型的指针变量,用来指向该类的唯一实例
- 用一个公有的静态方法来获取该实例,第一次调用该方法时,创建实例并返回(懒汉式),以后调用直接返回
- 用一个公有的静态方法来删除该实例,以保证该实例只会被删除一次。
#include <iostream>
using namespace std;
class A {
private:
A() {}; //构造和析构私有
~A() {};
public:
static A * GetInstance() {//公有静态方法,可以获取该唯一实例
if (NULL == m_pInstance) m_pInstance = new A; //(多线程需要加锁)
return m_pInstance;
}
static void DeleteInstance() {//公有静态方法,可以删除该实例
if (m_pInstance != NULL)
delete m_pInstance;
m_pInstance = NULL;
}
private:
static A *m_pInstance; //私有静态指针变量:指向类的唯一实例
int count; //其他成员变量...
};
A *A::m_pInstance = NULL; //懒汉式
//A *A::m_pInstance = new A; //饿汉式
int main() {
//A a; //错误,外部无法创建该类对象
A *pa = A::GetInstance(); //通过调用 类静态成员函数 来获取类对象
A *pb = A::GetInstance(); //可多次调用
cout << pa << pb << endl; //地址相同,pa,pb指向的是同一个对象
//delete pa; //错误,外部无法直接销毁该类对象
A::DeleteInstance(); //通过调用 类静态成员函数 来析构类对象
return 0;
}
myList
练习1
实现一个链表类:
- 带头结点
- 数据类型是Student类,学号起始编号是100
- 实现下列功能:
myList(const myList& other);//深拷贝构造
mylist &operator=(const myList &other);//赋值重载
void insert_tail(int_age, const string&_name);//尾插
bool del_node(int_id);//按id删除节点
void print() const;//遍历打印
inline int get_size() cosnt;//获取链表中元素个数
class myList{
private:
Student_node *head;
Student_node *tail;
int size;
};
class Student_node{
pravate:
int id;
int age;
std::strting name;
Student_node *next;
}
Student_node类(结点):
- 学号自动增长。static静态变量和静态函数
- Student_node类没有实现析构、拷贝构造、赋值运算符重载,可行吗?
- 假如学员姓名用自己写的String 类,那么要在哪里自己实现上面的那些函数?
- 声明了myList是Student_Node 的友元类,假如不允许使用友元,该类还需要提供那些函数?
class Student_node{
friend class myList;
public:
Student_Node(bool flag = flase, int _age = 20, const std::string & _name = “ ”):id(calc_id(flag)),age(_age), name(_name), next(NULL){}
static int calc_id(bool flag){
if(flag)
return now_id ++;
return 0;
}
pravate:
int id;
int age;
std::strting name;
Student_node *next;
private:
static int now_id ;
}
网友评论