标准库类型string
1.string表示可变长度的字符序列。
2.注意字符串是对象。
3.使用string类要包含头文件
特殊:string S4(“I am”)->>赋初值
“+” 字符串连接
“+=”未尾追加
S1.size()输出S1中的字符个数
4.遇空格或回车符结束(输入时,cin)。
5.scanner,printf不能使用。
6.getline()函数,只有遇到回车才结束。
例: string line;
while(getline(cin,line))
cout<<line<<endl;
7.读取单词,直到非正常输入结束
string word;
while(cin>>word)
cout<<word<<endl;
8.empty()判断string是否为空。
string line;
while(getline(cin,line))
if(!line.empty())//line不为空输出
cout<<line<<endl;
相同=长度+对应字符相同
大小=按字典顺序排
x=strlen(s1,c_str());
指针和引用
1.内存地址,每个字节都有唯一的地址。
内存是直接访问,通过变量名。地址是间接访问,即通过另外一个名字找到这个位置,进而找到该位置中的值。
2.指针:存储地址单元(目标变量的地址)
类型 * 指针变量;
类型是指针绑定目标对象的数据类型。
int pi;//指整型变量
int pi;//字符类型
(1)
int ival =120;
int *pi =&ival;
//pi指向ival;
//pi是ival的地址,即&ival;
*pi是ival的值;
(2)
int x=100,y=200;
int *pi =&x;
*pi =y;
//x=y; 将y赋值给pi指向的x;
(3)
int ival =1024;
int *pi =&ival;
int *pi =&pi;
//存放pi的地址;
4.指针不产生=异性;指针什么类型,就赋值的是什么类型。
5.指针为0时时空指针,允许
0 NULL()
重点:
(1)
定义指针时,应对指针进行初始化。
(2)
同类型指针可以进行相等不相等(同一目标变
量)结果是布尔类型。
(3)
指针可以进行加减(跨越四个字节),前提四个
字节后必须存在。
(4)
自增,自减运算运用于指向数组元素的指针。
6. void * 指针:通用指针。
7. 静态分配空间:编译时分配内存,有名字,可以直接操作。
8. 动态分配内存:只能通过指针间接操作。(无名字)
9. 绑定:定义变量时,赋初值,将其地址赋值给指针变量。
10.动态:new,delete用于动态管理。
new:在堆上分配空间,创建对象,并返回对象地址。
一般讲new返回的地址保存在指针变量中。
单个:new 类型。
多个:new 类型【数组大小】
new(指针) 类型
int ipa =new int【100】;
//ipa是首地址
不能对数组进行显示的初始化(复杂)。
数组大小不一定是常量,是数组元素个数,不是
字节数。
堆上使用后必须被delete释放。
单个:delete 指针;
delete 【】指针;//连续所有空间。
空悬指针:当解除绑定关系后,*pi =100;就是错的,不能再进行赋值。
引用:主要用作函数的参数。
引用由类型标识符和一个说明符(&)定义。
type& refVarible =leftValue;
//引用必须被初始化,初始值是一个有内存地址的对象。
int ival =100;
int &refVal =ival;
int &refVal2;//错误,无针对性
int &refVal3 =&ival;//错误
int &refVal4 =10;//错误
引用不能与常数或某个表达式绑定。
conse限定指针:
指向const对象的指针(非const)
const type *cp;
type const *cp;
cp是指向常量的指针,它所指向的内存中的内容不改变。即,cp值不改变。
type * const cp =。。。。。;
cp是常量指针,初始化后值不能改变。
const type const cp =。。。。。;
不能用非const引用指向const对象。
类
1.类包括行为和属性。其中行为就是成员函数,属性是数据成员。
2.命名格式:
class 类名
{
public:
公有数据成员和成员函数。
protected:
保护数据成员和成员函数。
private:
私有数据成员和成员函数。
};
各个成员函数的实现。
注意:在类定义完之后一定要加上;
例:
class Student
{
public:
void display();
private:
string name;
string id;
char sex;
int age;
double score;
};
注意:类的数据成员可以是其他类的对象(类的祖组合),但不能以类自身的对象作为本类的成员(不能嵌套),而类自身的指针和引用可以作为类的成员。
3.一般将成员函数声明为函数原型,在类外具体实现成员函数。
成员函数可以操作本类的数据成员以及函数内定义的局部变量,但一般不能操作全局变量。
4.类的成员函数通过操作数据成员实现功能。
定义:
返回值 类型 类名::成员函数名(参数表) //局部函数
{
函数体
}
注意:函数名称含两个单词,第一个首字母不大写,后一个大写 。
对象是类的实例或实体。
5.对象的定义:
类名 对象名1 对象名2 对象名3。。。。对象名n;
必须在定义类以后,才能定义类的对象。
对象成员的访问:
(1)对象名·公有成员
(2)对象指针变量---->公有成员
ptr->print();
a1=(ptr)·Getx();
注意:如果操作需要从外部引数据,加形参;如果只对数据成员操作,则不用加形参。
在类定义的过程中,不能对数据成员初始化。
6,内联函数
inline 函数原型
函数重载:函数名相同,但参数不相同(类型不同或个数不同)的一组函数—>操作时自动匹配
构造函数(类的成员函数)一定重载:用于创建对象的特殊成员函数,当创建对象时,系统自动调用构造函数。
作用:对对象分配不同;对数据成员赋初值;请求其他资源。
注意:用户没有定义构造函数时,系统自动提供缺省的构造函数。
(1)函数名=类名
(2)可以有任意类型的参数,但无返回值
析构函数:用于取消对象的成员函数
(1)~类名
(2)无参,无返回类型
默认构造函数:
类名::类名(){}
(1)创建对象
类名 对象名【(实参表)】;
–一定要按照定义构造函数的方式去创建,参数类型不匹配的创建方式都是错误的。
–要创建构造函数,一定要创建不带参数的构造函数(好匹配)
(2)利用指针和new
类名 * 指针变量 =new 类名【(实参表)】;
Date date1 =new Date(1998,4,28)
构造函数的初始化列表----数据成员初始化
(1)使用构造函数
—必须使用参数的初始化列表对数据成员进行初始化。
1)数据成员为常量
2)数据成员为引用类型
3)数据成员为没有无参构造函数的类的对象
----类成员初始化顺序
1)按数据成员在类中的声明顺序进行初始化
2)在创建对象时,构造函数被自动询问,起始数据成员赋初值的作用,不能在程序中显示调用
3)可以在程序任何地方显示调用对象set函数,修改对象的值
7.this指针
(1)每声明一个对象 ,系统就用一个空间来封装。
(2)成员函数是公用的。
8.类的特殊成员
(1)长成员
----数据成员被实例化后,其值不能改变
----在类成员函数说明后加const,则该成员函数成为常量成员函数(对数据成员只读不写)
----放在前面说明返回值是常量
例:
Date birthday=>复杂数据类型 =数据对象
code(num)绑定数据成员
----定义完常对象以后,对数据成员不能更改。
----对名字中有const的无用,只是名字而已。
9.类成员冠以static声明时,称为静态成员=>类成员
(1)静态数据成员为同类对象共享=>所有对象周期拥有一个空间。
(2)静态数据成员函数与静态数据成员协同操作
保证在不依赖于某个对象的情况下,访问静态数据成员。
例:
class A
{
int n;
static int s;//属于所有对象
}
=>定义完类以后,马上对静态成员进行初始化。
10.不能重载的运算符
. :: . ?: sizeof
限制:原有基本语义不变
—优先级
—结合性
—运算符所需的操作数
—创建新的运算符
运算符是在定义类的时候,以成员函数或友元函数出现
11.
一元运算符
object op 或 op object
重载为成员函数
object.operator op()
操作数由对象object通过this指针隐含传递
二元运算符
object op objectR
–>objectL. operator op(objectR)
左由object通过this指针传递,右由参数objectR传递
注意:
对象做参数时,一般采用引用的方式来传递(形参是复杂的类型)
12.class A{
public:
int a;
};
A a1;
A b1=a1;
b1=a1执行的是浅复制,此时a1.a和b1.a指向的是同一个内存地址,如果在析构函数里面有对内存的释放。就会出现内存访问异常。因为一块内存空间会被释放两次!
#include
#include <string.h>
using namespace std;
class person{
private:
char *name;
int age;
public:
person(const char *Name,int Age)
{
name=new char[strlen(Name)+1];
strcpy(name,Name);
age=Age;
cout<<“construct …”<<endl;
}
~person()
{
cout<<“destruct …”<<age<<endl;
delete name;
}
void dispaly()
{
cout<<name<<" "<<age<<endl;
}
void setage(int x)
{
age=x;
}
};
int main()
{
person p1(“test”,23);
person p2=p1;
p1.setage(10);
p1.dispaly();
p2.dispaly();
return 0;
}
从运行结果我们可以看到程序只是调用了一次构造函数,但是却执行了两次析构函数,不符合预期期望。对象p2=p1执行的是浅复制,p2中指针name和p1中指针name是指向的同一地址,由于没有定义构造函数,在执行p2=p1的时候,系统采用默认拷贝构造函数(默认的拷贝构造函数不会为新对象重新分配新的内存空间),即按位的拷贝方式将p1中各数据成员的值拷贝到p2的对应成员中,所以导致p1.name=p2.name(指向了同一内存),此时类person的构造函数只会执行一次。
当程序运行结束时,由析构函数执行的规律可知先构造的后执行,所以先执行p2的析构函数,此时系统将p2.name指向的存储单元释放,在执行p1析构函数的时候,p1.name所指向的内存单元又被释放,这样就会造成同一块内存空间被释放两次,造成错误,p1.name也就成了悬挂指针。
#include
#include <string.h>
using namespace std;
class person{
private:
char *name;
int age;
public:
person(const char *Name,int Age)
{
name=new char[strlen(Name)+1];
strcpy(name,Name);
age=Age;
cout<<“construct …”<<endl;
}
person(const person& oPerson) //copy构造函数
{
name=new char[strlen(oPerson.name)+1];
strcpy(name, oPerson.name);
age=oPerson.age;
cout<<"copy construct ..."<<endl;
}
~person()
{
cout<<"destruct ..."<<age<<endl;
delete name;
}
void dispaly()
{
cout<<name<<" "<<age<<endl;
}
void setage(int x)
{
age=x;
}
};
int main()
{
person p1(“test”,23);
person p2=p1;
p1.setage(10);
p1.dispaly();
p2.dispaly();
return 0;
}
13.()运算符用于函数调用
重载格式
类型 类::operator()(参数表)
例:
x(arg1,arg2.。。。)
注意:重载输出运算符"<<" (只能被重载成友元函数,不能重载成成员函数)
感想
我是一名转专业的学生,从一开始对计算机专业的懵懂到现在一步一步的学习认知,我发现这个专业真难。就c++这门学科来说,我从来没有这样害怕上这一门课,我感觉的是,我并不是完全听不懂,但就是写不出程序来,说实话我真的很害怕老师布置的作业的,就是每次做作业都听困难的,就发憷,我原以为语言没有说是很困难,但渐渐地发现基础就是得多写代码,将学到的落实才可以。怎么说呢 ,还是努力地不够,没当回事,再加把劲吧,多问多学!