当前位置: 首页 > wzjs >正文

上海建设三类人员网站购物网站界面设计

上海建设三类人员网站,购物网站界面设计,注册网站的公司名字,网站托管维护代运营目录 类的定义 类的定义 限定符说明 补充 类的实例化 类对象的大小 类中隐藏的this指针 this指针的引入 this指针的特性 类的默认成员函数 构造函数 特征 缺省值 默认构造函数 析构函数 特征 拷贝构造函数 特征 运算符重载 要求 赋值运算符重载 日期…

目录

类的定义

类的定义

限定符说明

补充

类的实例化

类对象的大小

类中隐藏的this指针

this指针的引入

this指针的特性

类的默认成员函数

构造函数

特征

缺省值

默认构造函数

析构函数

特征

拷贝构造函数

特征

运算符重载

要求

赋值运算符重载     

日期中的运算符重载

构造函数

日期的比较

日期+天数:+=

日期+天数:+

日期-天数:-=

日期前置++和后置++

日期-日期

内存管理

new和delete

与malloc和free的区别 

定位new

 补充

cout和cin

Date的cout和cin

初始化列表

静态成员变量

静态成员函数

匿名对象

模板,泛型编程

模板参数匹配原则


类的定义

C语言是面向过程的,关注的是过程,而C++则是面向对象的。面向过程就需要关注整个流程的实现的步骤和方法,面向对象则更关注实现某个事物参与的对象有哪些。

有时候不希望对外提供实现的方法及对象的属性,只希望向用户提供对应功能的接口,用户直接使用,C语言是无法做到对数据的封装的,所以C++引入类这一概念来实现

C语言的结构体只能定义变量,所以C语言的数据和数据的实现方法是分离的,这会导致我们既要传数据,又要传调用的结构体,很麻烦。C++的结构体既能定义变量,还能定义函数,这样就可以将数据及数据实现的方法进行有机结合。


类的定义

class name
{        //内体由变量及函数组成
};   //分号

class是定义类的关键字,name是类的名称。类的成员被称为内的属性和成员变量,类的函数称为类的实现方法或成员函数。

在C++中为了实现对数据进行封装,引入了访问访问限定符的概念。

限定符分为三种:1)public(公有);2)private(私有);3)protected(保护);

pubic修饰的类外可以直接访问,private和protected类外是不能直接访问的。

class test
{
public:int add(){return _x + _y;}
private:int _x;int _y;
};

限定符说明

1)限定符的作用域是从该限定符开始到下一个限定符,若没有下一个限定符,则直接到类结束;

2)class的访问权限中,public是公有,private和protected是私有;

3)struct中默认访问权限是public。class中默认访问权限是private;

补充

面向对象的三大特性:封装,继承,多态;

封装:将数据和操作数据的方法进行有机结合,隐藏对象的属性和实现细节,对外公开接口来和对象进行交互。封装的本质是更好的管理,让用户更方便的使用类。


类的实例化

用类模板定义对象的操作叫做类的实例化。

class test
{
public:int add(){return _x + _y;}
private:int _x;int _y;
};int main()
{test s1;  //类模板的实例化,s1就是类对象return 0;
}

定义出的类实际上是不会分配空间存储的,而类对象则需要空间进行存储;类就是图纸,而类对象就是依据图纸得到的产品。

类对象的大小

类是没有大小的,只有在类模板实例化后才有大小,类对象的大小是其成员变量经过内存对齐之后的大小。注意类函数是不加到类对象的大小,类函数是类中公有的,创建对象是不需要为其开辟空间,需要调用的时候直接去其地址处调用即可,就好比自己家和小区篮球场的关系,需要的时候直接去使用,自己不用再为其开辟空间。

注意:没有成员变量的类对象也需要1个字节的大小进行占位。


类中隐藏的this指针

this指针的引入

class test
{
public:void Init(int x, int y){_x = x;_y = y;}
private:int _x;int _y;
};int main()
{test t1;test t2;t1.Init(1, 2);t2.Init(3, 4);return 0;
}

上述两个test的类对象,在调用Init的时候,编译器是怎么将其分开的,在调用的时候,编译器怎么知道对t1还是t2进行处理的??

C++中引入了隐藏的this指针来解决这一问题。如上图所示,t1和t2都有其this指针分别是&t1和&t2,通过这种方式来区分是哪一个对象在调用类函数。

this指针的特性

1)this指针是不能显示调用的,但是在类函数内部是可以显示使用的;

class test
{
public:void Init(int x, int y){this->_x = x;  //其本意就是,_x=x;this->_y = y;}
private:int _x;int _y;
};

2)this指针实际上是,成员函数的形参,当调用成员函数的时候,将对象地址作为实参传递给this形参。所以对象中是不储存this指针的。

3)this指针作为形参不需要用户自己传,编译器会自动传递。


类的默认成员函数

类为了解决每次实例化对象后都要调用构造,开辟空间,出作用域又要销毁等问题,类设置了6个默认成员函数,其可以由编译器自动调用。


构造函数

构造函数是为了解决忘记对类对象进行初始化的问题。构造函数是一种特殊的类成员函数;

特征

1)函数名与类名相同;

2)无返回值;

3)对象实例化时编译器会自动调用对应的构造函数;

4)构造函数可重载。

5)如果类中没有显示写构造函数,则C++编译器会自动生成一个无参的默认构造函数,一旦用户显示定义编译器就不会再生成了。对于编译器生成的默认构造函数,内置类型不做处理,自定义类型会去调用其本身的默认构造函数。

class test
{
public:test(int x =10,int y=20){_x = x;_y = y;}private:int _x;int _y;
};

构造函数也是函数,所以根据不同需求可以对构造函数进行重载。

什么时候要自己写构造函数呢??一般情况下类成员中由内置类型的成员就需要写默认构造函数,全是自定义类型成员时,就不需要写构造函数,让编译器自己生成。

缺省值

为了解决对内置类型,编译器不处理问题,可以自己写构造函数,也可以提供缺省值让编译器生成默认构造函数时使用。

class test
{private:int _x =10;int _y =20;
};

通过给_x和_y缺省值,编译器在调用默认构造时就会将其初始化。

默认构造函数

默认构造函数实际上分为3种:1)编译器默认生成的;2)全缺省的,有缺省值且每个形参都有;3)无参数的,构造函数没有参数。


析构函数

析构函数是对类对象中资源的销毁,大多数是进行动态内存的销毁。

特征

1)析构函数,函数名前加~;

2)无参数,无返回值;

3)对象的生命周期结束时,系统会自动调用析构函数。

4)一个类只能有一个析构函数,若未定义,系统会自动生成默认的析构函数,析构函数不能重载;默认析构函数对内置类型不处理,对于自定义类型去调用其自己的析构函数。

class test
{
public:~test(){//销毁}
private:};

什么时候需要使用析构函数??一般情况下,有动态开辟的空间,要显示写析构函数,当需要释放的资源都是内置类型的,不写析构函数。


拷贝构造函数

特征

1)拷贝构造函数是析构函数的一个重载;

2)拷贝构造函数的参数只有一个且必须是类类型对象的引用,使用传值方式编译器会直接报错,因为将实参赋值给形参的时候需要调用拷贝构造完成,这就会导致死循环的调用拷贝构造。

3)但不写拷贝构造函数时,编译器会自动生成默认拷贝构造,默认拷贝构造对内置类型按照其字节数进行拷贝,对自定义类型会调用其默认的拷贝构造函数。内置类型的这种拷贝也被称为浅拷贝或值拷贝。如果类中有指针,对指针进行浅拷贝的时候就会导致,两个类对象指向同一块空间。

class Date
{
public://默认构造函数Date(int year = 1, int month = 1, int day = 1){_year = year;_month = month;_day = day;}//拷贝构造函数Date(const Date& d){_year = d._year;_month = d._month;_day = d._day;}
private:int _year;int _month;int _day;
};

运算符重载

C++为增强代码的可读性,引入了运算符重载,运算符重载是有特殊函数名的函数,其也有返回值和类型。关键字operator后面接需要重载的运算符符号即可。

函数原型:返回值类型 operator 操作数(参数列表);

bool operator <(const Date& d)
{//有隐藏的this指针,_year,_month,_day又属于this指针指向的类对象if (_year < d._year)return true;if (_year == d._year && _month < d._month)return true;if (_year == d._year && _month == d._month&&_day<d._day)return true;return false;
}

以上对<的运算符重载,就可以直接实现Date类对象的比较。

要求

1)不能用一些特殊符号作为操作符,eg:@,#等;

2)重载操作符必须有一个类类型参数;

3)用于内置类型的运算符,其含义不能变,eg:重载+后还是加;

4)作为类成员函数重载时,其形参看起来比操作数少一个,因为成员函数的第一个参数为隐藏的this指针;

5).*     ::    sizeof    ?:(三目)   . 这5个关键字不能重载。

赋值运算符重载     

赋值运算符重载是对两个已经初始化后的类对象进行赋值。

class Date
{
public:bool operator =(const Date& d){_year = d._year;_month = d._month;_day = d._day;}private:int _year;int _month;int _day;
};

以上赋值运算符重载就可以实现对不同类对象间的赋值。


日期中的运算符重载

构造函数

class Date
{//默认构造函数Date(int year=1, int month=1, int day=1){_year = year;_month = month;_day = day;}//拷贝构造函数Date(const Date& d){_year = d._year;_month = d._month;_day = d._day;}private:int _year;int _month;int _day;
};

日期的比较

在设置运算符重载的时候,可以直接看出运算符之间的关系,从而直接调用其他已经实现的运算符来设置新的运算符。

bool operator <(const Date& d)
{if (_year < d._year)return true;if (_year == d._year && _month < d._month)return true;if (_year == d._year && _month == d._month && _day < d._day)return true;return false;
}
bool operator==(const Date& d)
{if (_year == d._year && _month == d._month && _day == d._day)return true;return false;
}
bool operator!=(const Date& d)
{return !((*this) == d);
}bool operator<=(const Date& d)
{if ((*this) == d || (*this) < d)return true;return false;
}
bool operator>(const Date& d)
{return !((*this) <= d);
}
bool operator>=(const Date& d)
{return !((*this) < d);
}

日期+天数:+=

通过日期加天数来获取未来的某一天的日期。

int Getmonthday(int year, int month)
{int monthday[13] = { 0,31,28,31,30,31,30,31,31,30,31,30,31 };if (month == 2 && ((year % 4 == 0 && year % 100 != 0) || year % 400 == 0))return 29;return monthday[month];
}
Date& operator+=(int day)
{_day += day;int nday = Getmonthday(_year, _month);while (_day > nday){_day -= nday;_month++;if (_month == 13){_year++;_month = 1;}nday = Getmonthday(_year, _month);}return *this;
}

日期+天数:+

Date operator+(int day)
{Date tmp(*this);  //通过拷贝构造一个新类对象进行返回tmp._day += day;int nday = Getmonthday(tmp._year, tmp._month);while (tmp._day > nday){tmp._day -= nday;tmp._month++;if (_month == 13){tmp._year++;tmp._month = 1;}nday = Getmonthday(tmp._year, tmp._month);}return tmp;
}

日期-天数:-=

Date& operator-=(int day)
{_day -= day;_month--;  //向将month-1,向前加日期int nday = Getmonthday(_year, _month);while (_day < 0){_day += nday;if (_day > 0)break;_month--;if (_month == 0){_year--;_month = 12;}nday = Getmonthday(_year, _month);}return *this;
}

日期前置++和后置++

//前置++
Date& operator++()
{(*this) += 1;  //直接调用+=return *this;
}
//后置加加
Date operator++(int)  //为了与前置++分开,在参数中给一个int类型参数
{Date tmp(*this);*this += 1;return tmp;
}

日期-日期

通过日期-日期来获得两个日期间的天数,日期-日期可以直接用计数器,每次+1看加了多少次。

//日期-日期
int operator-(Date d)
{Date max(*this);Date min(d);if (max < min){max = min;min = *this;}int n = 0;while (min != max){min++;  //直接用计数,每次++,看加多少次n++;}return n;
}

内存管理

new和delete

C++中引入新的关键字new和delete来对动态内存进行管理。

C++中申请和释放单个内存空间用new和delete,多个内存空间用new[ ]和delete[ ] 。

int* pt1 = new int;     //开辟一个int的动态内存空间
delete pt1;int* pt2 = new int(10); //开辟并初始化为10 
delete pt2;int* pt3 = new int[10]; //开辟10个int类型的空间
delete[] pt3;int* pt4 = new int[10] {1,2,3,4,5};  //开辟并依次初始化
delete[] pt4;

new对比malloc的优势是:对于自定义类型new会顺便调用类的构造函数,不需要我们手动再进行初始化了,同样delete对于自定义类型也会调用析构函数。

了解:C++是面向对象的语言,所以new失败后,不会像C语言一样用NULL返回值,C++更喜欢抛异常。

与malloc和free的区别 

1)new和delete会对自定义类型调用构造和析构函数;

2)new和delete是关键字,malloc和free是函数;

3)new不用走动计算开辟空间的大小,malloc要手动计算;

4)new可以直接返回要开辟类型对应的指针,malloc返回的是void*还要强转;

5)开辟空间失败,new是抛异常,而malloc是返回NULL。

定位new

对于已经开辟好的空间,可以使用定位new来对空间调用析构函数。

定位new参与内存池搭配使用。用法如下。

class A
{
public:A(int a):_a(a){}
private:int _a;
};int main()
{A* pa = (A*)malloc(sizeof(A));new(pa)A(1);//new(空间地址)自定义类型(传给构造函数的参数)return 0;
}

 补充

cout和cin

cout和cin之所以能够实现类型的自动匹配,因为cout和cin库中有其对应的各个类型的重载函数,实际上也可以用运算符重载实现用cout和cin处理自定义函数。

此时就不能再间重载函数放在类中定义了,为什么???因为类中有隐含的this指针,当还是在类中定义重载,就会导致需要d1<<cout这样使用输出,而我们希望的是cout<<d1来使用,所以就要在类外面定义重载函数。但是在外面定义重载函数就不能使用类的私有成员了,此时要通过声明友元函数来实现对类私有成员的访问。

友元函数就是在类中声明自定义函数,其前面再加上friend;

Date的cout和cin

istream和ostream分别是cout和cin的类型。 

class Date
{friend ostream& operator<<(ostream& out, const Date& d);friend istream& operator>>(istream& in, Date& d);private:int _year;int _month;int _day;
};using std::ostream;
using std::istream;
using std::endl;
ostream& operator<<(ostream& out, const Date& d)
{out << d._year << " " << d._month << " " << d._day << endl;
}
istream& operator>>(istream& in, Date& d)
{in >> d._year >> d._month >> d._day;
}

初始化列表

在C++中类的有些成员变量是必须在初始化列表中初始化,在构造函数中是无法完成初始化的,初始化列表实际上是构造函数的一部分,是类对象成员定义的位置。

必需在初始化列表中初始化

1)引用成员变量;

2)const修饰的成员变量;

3)没有默认构造的自定义类型成员变量。

class test
{test(int& x):a(x)   //将a引用为x,b(2)   //将b赋值为2{}private:int& a;const int b;
};

注意:在初始化列表中初始化的顺序不是按照代码顺序进行的,而是按照类成员声明的顺序向下进行的。

静态成员变量

类中的静态成员变量和普通成员变量的主要区别在于:普通成员变量属于每个类对象,储存在对象里面,而静态成员变量属于类,是公有的存储在静态区。

静态成员需要在类中声明,在类外定义。

class test
{
private:int a;int b;static int st;
};int test::st = 0;

静态成员函数

静态成员函数与普通成员函数的区别是,其没有隐藏的this指针,所以调用静态成员函数要用类域和访问限定符实现。同时因为没有this指针,其不能访问类中的私有成员及其他的非静态成员函数。

匿名对象

当我们只是临时需要创建一个对象,只要求在这一行使用该对象时,就可以创建匿名对象。

class A
{
public:A(int a):_a(a){}
private:int _a;
};int main()
{A aa(1);  //有名对象A(1);     //匿名对象return 0;
}

有名对象的生命周期是当前函数局部域,匿名对象的生命周期是当前行。

补充:匿名对象和临时变量一样,具有常性,引用时要带const修饰,当对匿名对象进行引用时,可以延长匿名对象的生命周期,生命周期变为当前函数局部域。

模板,泛型编程

在C语言中有时候因为类型不同要写多个重复的函数,C++为了解决这一问题引入了模板,泛型编程的概念。

泛型编程:编写与代码类型无关的通过代码,是代码复用的一种手段。模板是泛型编程的基础。

函数模板的格式:template<typename T1,typename T2...typename Tn>

                            返回值 函数名(参数列表){ }

template<typename T>
void Swap(T& x, T& y)
{T tmp = x;x = y;y = tmp;
}

以上代码就是交换函数的模板,T相当于可以自动识别各个类型。typename是定义模板参数的关键字,也可以用class。

注意:函数模板实际上只是一张蓝图,其本身不是函数;在编译器编译阶段,编译器首先会识别实参的类型来推演生成对应类型的函数以供调用。

 对于类模板来说,类名和类型是不一样的。eg:stack是类名,stack<int>是类型。

模板参数匹配原则

1)一个非模板参数可以和一个同名的模板参数同时存在,并且该模板参数可以实例化为该非模板参数;

void Swap(int& x, int& y)
{int tmp = x;x = y;y = tmp;
}template<typename T>
void Swap(T& x, T& y)
{T tmp = x;x = y;y = tmp;
}int main()
{int a = 10, b = 20;Swap<int>(a, b);  //让模板函数实例化为与会模板函数相同的函数return 0;
}

2)对于非模板函数和同名的模板函数来说,如果其他条件都相同,在调用时会优先调用非模板函数。当模板函数能够实例出一个更匹配的,则调用模板函数。

void Swap(int& x, int& y)
{int tmp = x;x = y;y = tmp;
}template<typename T1,typename T2>
void Swap(T1& x, T2& y)
{T1 tmp = x;x = y;y = tmp;
}int main()
{int a = 10, b = 20;double c = 1.1;Swap(a, b);   //调用非模板函数Swap(a, c);   //调用模板函数return 0;
}
http://www.dtcms.com/wzjs/816813.html

相关文章:

  • 邢台网站制作网站布局设计规则
  • 运动网站建设主题做网站的前途怎么样
  • 怎么建立一个个人网站wordpress超级菜单
  • 深圳网站建设工资专业建网站平台
  • 用个人的信息备案网站网站建设工作稳定吗
  • 网站后台管理系统栏目位置展厅设计公司展厅效果图
  • 游戏网站首页设计wordpress html插件安装
  • 房产中介网站开发费用国外模板网站
  • 北京网站开发建设子域名网址查询
  • 安庆市建设局网站wordpress 评论 不好
  • asp网站域名凡科互动h5
  • 网站排名优化推广厦门wordpress文章默认模板名叫什么
  • 赶集网免费发布信息网重庆seo推广外包
  • 天河企业网站建设三亚旅游
  • 网站要多少钱学计算机网站建设
  • 门户网站的重要性国外毕业设计网站
  • 网站与手机app是一体吗西安网站制作费用
  • 做嗳啪啪 网站为什么不建议去外包公司
  • 建筑网红化海口seo推广公司
  • 上海找做网站公司哪家好推广做网站莱芜
  • 旅游网站建设项目规划书站内关键词自然排名优化
  • 安卓网站开发前景网站设计上市公司
  • 织梦网站修改首页图片网站建设 回本
  • 重庆制作网站首页十大免费看盘软件
  • 网站备案过户关键词优化网站
  • 网站备案查询不了北京网站开发怎么做
  • 美食网站建设合同范例外贸行业建站
  • 新媒体、网站建设 管理规范海外广告优化师
  • 国外的电商网站建设工程信息在哪个网站
  • 如何判断网站html5甪直做网站