/******************************************************************************************************************/

一、C++类的引入

与C相比,

1.编译使用g++代替 gcc,执行在linux中还是一样的

2.c++里面也有struct并对其进行了扩展,struct中的函数可以直接使用其成员,并可在struct中直接实现,

例:

struct person {

char *name;

int age;

char *work;

void printInfo(void)

{

printf("name = %s, age = %d, work = %s\n", name, age, work);

}

};

int main(int argc, char **argv)

{

struct person persons[] = {

{"zhangsan", 10, "teacher"},

{"lisi", 16, "doctor"},

};

persons[0].printInfo();

persons[1].printInfo();

return 0;

}

3.这样的struct可以使用class代替,注意权限问题,class还有新的特性,

例:

class person {

public:

//注意权限问题

char *name;

int age;

char *work;

void printInfo(void)

{

printf("name = %s, age = %d, work = %s\n", name, age, work);

}

};

/******************************************************************************************************************/

二、C++基础知识_访问控制

C++有三种访问权限private,protected,public

1.默认权限是private

2.对象的创建

类 对象

例:Person mPer;

3.访问本类中的属性,使用this->

由于c和c++里面有就近原则,所以这样就可以使用同名

访问父类的属性,直接使用该属性名即可(或者使用 父类名::属性名 的方式来访问)

/******************************************************************************************************************/

三、C++基础知识_程序结构

1.类中的成员函数在类中可不定义只是声明,实现放在类外面(类名 :: 函数名)

例:

class Person {

private:

char *name;

int age;

char *work;

public:

void setName(char *name);

int setAge(int age);

void printInfo(void);

};

void Person::setName(char *name)

{

this->name = name;

}

int Person::setAge(int age)

{

if (age < 0 || age > 150)

{

this->age = 0;

return -1;

}

this->age = age;

return 0;

}

void Person::printInfo(void)

{

printf("name = %s, age = %d, work = %s\n", name, age, work);

}

int main(int argc, char **argv)

{

Person per;

//per.name = "zhangsan";

per.setName("zhangsan");

per.setAge(200);

per.printInfo();

return 0;

}

2. 实现放在类外面,这样就可以优化整个程序结构,

把类的定义(函数成员只是声明)放在头文件中

使用者包含这个头文件,就知道怎么用了(不去关心具体实现)

具体实现放在具体实现文件里,包含对应头文件。

Linux下的编译方式

person: main.o person.o

g++ -o $@ $^     //$@表示person(目标),$^表示所有的依赖

%.o : %.cpp

g++ -c -o $@ $<    //$<表示第一个依赖

3.为防止出现函数名一致(函数名重复),导致不知道具体使用哪一个函数,引入命名空间namespace,

1).用法:

在定义和声明的地方,用namespace包含起来,例

namespace A

{

}

2).调用的时候使用A::函数名

注意使用A中的类创建对象也要加上A,即A::Person per;

per.setName();

3).如果命名空间之间的类名没有冲突,

类创建对象是可以不使用A::Person per;

使用using声明,即using A::Person;(一般放在文件前面)

文件前面代表的是全局命名空间,所以

/* 把A::Person放入global namespace, 以后可以使用Person来表示A::Person */

4).如果命名空间之间的类名没有冲突,

也可以使用using编译,即using namespace A;(一般放在文件前面)

把A空间里面所有的内容都导进来

出现冲突的地方必须指明函数所在的命名空间(A::函数名)

4.C++打印使用cout<<endl; 代替printf,

例:

std::cout<<"name = "<<name<<" age = "<<age<<" work = "<<work<<std::endl;

注意

1).需包含头文件

#include <iostream>

2).由于使用了命名空间,要指明cout的命名空间为标准命名空间里的

std::cout<<"name = "<<name<<" age = "<<age<<" work = "<<work<<std::endl;

或在文件前面指明using namespace std;

/******************************************************************************************************************/

四、C++基础知识_重载_指针_引用

1.重载

函数名一样,参数不一样

2.指针

与C语言一样

3.引用(类似内存地址,使用和变量名一样)

C++引入引用就是为了避免使用指针(防止指针使用不恰当),其实就是操作同一块内存

例:

int a=100;

int &b=a;//b就是a的引用

b是a的别名,操作b也就是操作a

定义:

int add_one_ref(int &b)

{

b = b+1;

return b;

}

使用:cout<<add_one_ref(a)<<endl;

注意,引用定义的时候就必须初始化,即赋值,同时引用是变量的别名,所以只能使用变量来赋值

/******************************************************************************************************************/

五、C++基础知识_构造函数

1.构造函数:在类中,和类名名字相同的函数,可以带参数也可不带

1).带参数的,创建对象时可传入,

Person per("zhangsan", 16);

2).无传入参数的,

Person per2;

//Person per2();//不使用这个,这个表示的是函数名为per2的函数的声明

2.不想写很多的重载的构造函数的情况

Person(char *name, int age, char *work = "none")

{//表示如果没有传入第三个参数,则第三个参数为"none"

cout <<"Pserson(char*, int)"<<endl;

this->name = name;

this->age = age;

this->work = work;

}

Person per("zhangsan", 16);//导致this->work ="none"

3.除Person per("zhangsan", 16);方式外,创建对象的方式

使用指针的方式:

Person *per4 = new Person;

//这两种创建对象的方式一样,都是调用无参构造函数

Person *per5 = new Person();

//这两种创建对象的方式一样,都是调用无参构造函数

Person *per6 = new Person[2];

//per6是个对象数组,数组成员是对象

Person *per7 = new Person("lisi", 18, "student");

Person *per8 = new Person("wangwu", 18);

per.printInfo();

per7->printInfo();

per8->printInfo();

//动态创建的对象(new出来的对象),整个程序(进程)执行完后会自动释放所有对象占用的内存空间(包括子函数中创建的对象),如果要手动释放,可以用delete命令:

delete per4;

delete per5;

delete []per6;

//对象数组的删除

delete per7;

delete per8;

//不是new的对象,局部变量:函数执行完会自动销毁,全局变量:一直存在

4.分配堆空间,使用new代替malloc

分配:

this->name = new char[strlen(name) + 1];

strcpy(this->name, name);

释放:

delete this->name;

linux中,free命令查看空闲内存

5.析构函数(只能有一个)

释放对象时,对象所占据的内存释放了,如果对象的函数成员中又new了对象,同时又没有对函数成员中new的对象delete,那么就会造成内存泄漏。

比较方便解决这个问题,就是引入析构函数,析构函数中加入对函数成员中new的对象的delete操作,这样delete对象时就释放了函数成员中new的对象(delete销毁对象的同时就会调用析构函数)

例:

~Person()

{

if (this->name)

delete this->name;

if (this->work)

delete this->work;

}

注意使用new创建的对象,用完要用delete释放

6.默认拷贝构造函数

拷贝构造函数和赋值函数的区别:拷贝构造函数是在对象被创建时调用的,而赋值函数只能被已经存在了的对象调用。

String a("A");

String b("B");

String c = a; // 调用了拷贝构造函数,最好写成c(a);

c = b; // 调用了赋值函数

拷贝构造函数分为深拷贝和浅拷贝,深浅拷贝:https://blog.csdn.net/libin66/article/details/53140284

无参数时,默认构造函数

有对象作为参数时,默认拷贝构造函数(进行值的拷贝,即浅拷贝) //C++类有四个默认函数---构造函数、拷贝构造函数(浅拷贝)、析构函数、赋值函数(浅拷贝):https://blog.csdn.net/anye3000/article/details/6570445)

Person per("zhangsan", 18);

Person per2(per);// 有对象参数, per是对象

默认拷贝构造函数,会改变其中的值,则在释放的时候,同一个值对应的堆空间会被释放两次,所以要定义自己的拷贝构造函数

Person(Person &per)

{

cout <<"Pserson(Person &)"<<endl;

this->age = per.age;

this->name = new char[strlen(per.name) + 1];//重新分配空间,如果是默认拷贝构造函数,就会进行值的拷贝,即这个指针的值等于传进来对象成员指针的值,导致不同对象指向同一个空间,从而导致内存释放时会释放两次

strcpy(this->name, per.name);

this->work = new char[strlen(per.work) + 1];

strcpy(this->work, per.work);

}

7.对象的构造顺序

1).创建对象首先是全局变量(在main函数执行之前),然后碰到哪个就创建哪个(不管是否静态),即按运行中定义对象的顺序调用构造函数。

由于静态对象的生存周期,退出函数不会被销毁,同时再次进入函数由于已经创建了也不会再次创建,即只定义一次

2).类中的数据成员是对象的情况,

I、先调用成员对象的构造函数,再调用自己的构造函数。

调用成员对象的无参构造函数,无需添加什么会自动调用

II、调用成员对象(数据成员是对象)的有参构造函数的方法

在自己类的构造函数后面加上:号,例:

class Student {

private:

Person father;//定义顺序

Person mother;

int student_id;

public:

Student()

{

cout<<"Student()"<<endl;

}

Student(int id, char *father, char *mother, int father_age = 40, int mother_age = 39) : mother(mother, mother_age), father(father, father_age)

{//加上:号就会去调用father对象的有参构造函数,修改:号后面的对象顺序不影响构造顺序,构造顺序按照定义的顺序,即先father,再mother,最后自己的

cout<<"Student(int id, char *father, char *mother, int father_age = 40, int mother_age = 39)"<<endl;

}

~Student()

{

cout<<"~Student()"<<endl;

}

};

III、析构函数的调用顺序

和构造函数的调用顺序相反

/******************************************************************************************************************/

六、C++基础知识_静态成员_友员

静态成员是属于类的(放在类的类名空间中),只占一份空间,不属于对象

1.类中定义

private:

static int cnt; //静态成员

public:

static int getCount(void)

{ //静态成员用于访问静态成员变量

//静态成员函数不能访问非静态成员变量(还没定义分配)

return cnt;

}

2.使用

一般使用成员函数访问:Person::getCount()

如果是公有属性,也可以Person::cnt;

3.class是struct的进化,所以还需要分配空间

int Person::cnt = 0; /* 定义和初始化 不再需要加static*/

//同时要放在main之前(放在main内会编译出错),因为要在创建对象之前就定义和初始化

4.也可以在类外定义静态成员函数

public:

static int getCount(void);//类内部声明

int Person::getCount(void)

{ //类外部定义,不再需要加static

return cnt;

}

5.也可以使用类的实例化对象调用静态成员函数

cout << "person number = "<<Person::getCount()<<endl;

cout << "person number = "<<p[0].getCount()<<endl;//类的实例化对象调用静态成员函数

cout << "person number = "<<p[1].getCount()<<endl;

6.友元

1.Point(int x, int y) : x(x), y(y) {}

等价于

Point(int x, int y){this->x=x,this->y=y}

2.类的友元函数(该函数一般会操作该类)可以直接访问该类的私有成员

1)首先在类中声明是友元函数

class Point

{

private:

int x;

int y;

public:

Point() {}

Point(int x, int y) : x(x), y(y) {}

int getX(){ return x; }

int getY(){ return y; }

void setX(int x){ this->x = x; }

void setY(int y){ this->y = y; }

void printInfo()

{

cout<<"("<<x<<", "<<y<<")"<<endl;

}

friend Point add(Point &p1, Point &p2);

};

2)友元函数就可以直接使用类的私有成员了

Point add(Point &p1, Point &p2)

{

Point n;

n.x = p1.x+p2.x;

n.y = p1.y+p2.y;

return n;

}

/******************************************************************************************************************/

七、C++基础知识_运算符重载_类外函数

1.加减乘除运算的重载

例如+号的重载

1).定义:

Point operator+(Point &p1, Point &p2)

{

cout<<"Point operator+(Point &p1, Point &p2)"<<endl;

Point n;

n.x = p1.x+p2.x;

n.y = p1.y+p2.y;

return n;

}

2).使用

Point p1(1, 2);

Point p2(2, 3);

Point sum = p1+p2;

2.++p,p++的重载

1).定义:

/* Point p(1,2); ++p; */

Point operator++(Point &p)

{

cout<<"++p"<<endl;

p.x += 1;

p.y += 1;

return p;

}

/* Point p(1,2); p++; */

Point operator++(Point &p, int a)

{//参数不同实现重载

cout<<"p++"<<endl;

Point n;

n = p;

p.x += 1;

p.y += 1;

return n;

}

2).使用

Point p1(1, 2);

Point p2(2, 3);

Point n = ++p1;

n.printInfo();

p1.printInfo();

cout << "******************"<<endl;

Point m = p2++;

m.printInfo();

p2.printInfo();

4.返回值是对象时,返回时会创建临时对象的问题(临时对象是局部变量用完又会被销毁)

/* Point p(1,2); ++p; */

Point operator++(Point &p)

{

cout<<"++p"<<endl;

p.x += 1;

p.y += 1;

return p;//返回引用,返回类型又是对象,系统就会自动创建临时对象,用完销毁(整个过程会调用构造函数与析构函数,浪费时间)

}

改进:

/* Point p(1,2); ++p; */

Point& operator++(Point &p)

{//使用引用则不会再去创建

cout<<"++p"<<endl;

p.x += 1;

p.y += 1;

return p;//使用引用则不会再去创建

}

Point operator++(Point &p, int a)

{//参数不同实现重载

cout<<"p++"<<endl; //endl表示换行

Point n;

n = p;

p.x += 1;

p.y += 1;

return n;//已经创建了n(已经有临时变量了)则不会再去创建临时对象

}

5.使用返回对象还是引用,取决于是否影响程序执行结果

引用返回效率高,在不影响运算结果则效率优先,即使用引用

6.<<的重载(<<也是运算符)

1)定义

ostream& operator<<(ostream &o, Point p)

{

cout<<"("<<p.x<<", "<<p.y<<")";//不需要换行

return o;

}

2)使用

cout<<m<<" "<<n<<endl;

//<<m表示执行<<m,并将结果输出到ostream

//<<m<<n表示把先执行<<m得到的ostream与n一起作为<<的参数,从而得到新的ostream引用,即<<n执行的结果追加到之前执行的<<m的结果后面

//cout<<m<<" "<<n<<endl,表示cout使用 执行<<m<<" "<<n<<endl的返回值,即<<m<<" "<<n<<endl的返回值输出到cout

7.运算符重载函数可直接调用

operator++(p1,0);//后一个参数随便传入值,只是为了分辨

operator<<(cout,p1);

/******************************************************************************************************************/

八、C++基础知识_运算符重载_成员函数

1.类中定义重载函数

Point operator+(Point &p)

{

cout<<"operator+"<<endl;

Point n;

n.x = this->x + p.x; //类中所以可以这么用 p.x

n.y = this->y + p.y;

return n;

}

/* Point p(1,2); ++p; */

Point& operator++(void)

{

cout<<"operator++(void)"<<endl;

this->x += 1;

this->y += 1;

return *this; //返回别名,变量名

}

/* Point p(1,2); p++; */

Point operator++(int a)

{

cout<<"operator++(int a)"<<endl;

Point n;

n = *this;

this->x += 1;

this->y += 1;

return n;

}

2.使用

Point p1(1, 2);

Point p2(2, 3);

Point m, n;

m = p1 + p2; /* m = p1.operator+(p2); */

cout<<"add p1,p2 = "<<m<<endl;

cout<<"begin"<<endl;

m = ++p1;    /* m = p1.operator++(); */

cout<<"m = "<<m<<" "<<"p1 = "<<p1<<endl;

cout << "******************"<<endl;

n = p1++;    /* m = p1.operator++(0); */

cout<<"n = "<<n<<" "<<"p1 = "<<p1<<endl;

cout<<"end"<<endl;

3.重载等号

对象拷贝时,可能会导致两个对象中的指针指向同一块内存,就有可能导致同一块内存被释放两次(或者覆盖导致,导致原有的内存泄漏)

重载等号可解决这个问题

1.类中定义

Person& operator=(const Person& p)

{

cout << "operator=(const Person& p)"<<endl;

if (this == &p)

return *this;

this->age = p.age;

if (this->name)

{

delete this->name;

}

if (this->work)

{

delete this->work;

}

this->name = new char[strlen(p.name) + 1];

strcpy(this->name, p.name);

this->work = new char[strlen(p.work) + 1];

strcpy(this->work, p.work);

return *this;

}

2.使用

const Person p1("zhangsan", 10);

cout<<"Person p2 = p1" <<endl;

Person p2 = p1;

//调用拷贝构造函数,没有调用重载等号函数

//注意拷贝构造函数的参数要加上const,来兼容只读的const参数(const对象作为参数)const对象只能调用const函数(函数声明后加上const,表示这个函数不会有修改的操作,不会修改类中的变量)

Person p3;

cout<<"p3=p1"<<endl;

p3 = p1;//调用重载等号函数

cout<<"end"<<endl;

//p3=(p2=p) 再次赋值的情况,所以重载函数需要返回值

C++之基础知识20170830的更多相关文章

  1. .NET面试题系列[1] - .NET框架基础知识(1)

    很明显,CLS是CTS的一个子集,而且是最小的子集. - 张子阳 .NET框架基础知识(1) 参考资料: http://www.tracefact.net/CLR-and-Framework/DotN ...

  2. RabbitMQ基础知识

    RabbitMQ基础知识 一.背景 RabbitMQ是一个由erlang开发的AMQP(Advanced Message Queue )的开源实现.AMQP 的出现其实也是应了广大人民群众的需求,虽然 ...

  3. Java基础知识(壹)

    写在前面的话 这篇博客,是很早之前自己的学习Java基础知识的,所记录的内容,仅仅是当时学习的一个总结随笔.现在分享出来,希望能帮助大家,如有不足的,希望大家支出. 后续会继续分享基础知识手记.希望能 ...

  4. selenium自动化基础知识

    什么是自动化测试? 自动化测试分为:功能自动化和性能自动化 功能自动化即使用计算机通过编码的方式来替代手工测试,完成一些重复性比较高的测试,解放测试人员的测试压力.同时,如果系统有不份模块更改后,只要 ...

  5. [SQL] SQL 基础知识梳理(一)- 数据库与 SQL

    SQL 基础知识梳理(一)- 数据库与 SQL [博主]反骨仔 [原文地址]http://www.cnblogs.com/liqingwen/p/5902856.html 目录 What's 数据库 ...

  6. [SQL] SQL 基础知识梳理(二) - 查询基础

    SQL 基础知识梳理(二) - 查询基础 [博主]反骨仔 [原文]http://www.cnblogs.com/liqingwen/p/5904824.html 序 这是<SQL 基础知识梳理( ...

  7. [SQL] SQL 基础知识梳理(三) - 聚合和排序

    SQL 基础知识梳理(三) - 聚合和排序 [博主]反骨仔 [原文]http://www.cnblogs.com/liqingwen/p/5926689.html 序 这是<SQL 基础知识梳理 ...

  8. [SQL] SQL 基础知识梳理(四) - 数据更新

    SQL 基础知识梳理(四) - 数据更新 [博主]反骨仔 [原文]http://www.cnblogs.com/liqingwen/p/5929786.html 序 这是<SQL 基础知识梳理( ...

  9. [SQL] SQL 基础知识梳理(五) - 复杂查询

    SQL 基础知识梳理(五) - 复杂查询 [博主]反骨仔 [原文]http://www.cnblogs.com/liqingwen/p/5939796.html 序 这是<SQL 基础知识梳理( ...

随机推荐

  1. https双向认证网站搭建

    新建网站 在搭建网站证书之前,我们先搭建好我们的网站 1.网站基本搭建 为我们的项目新建一个网站,按照如下的步骤来 1,打开IIS,右键单击网站弹出菜单,选择网站(如图1.1.1) 图1.1.1 2, ...

  2. artDialog基本使用

    artDialog是一个基于javascript编写的对话框组件,它拥有精致的界面与友好的接口l  自适应内容artDialog的特殊UI框架能够适应内容变化,甚至连外部程序动态插入的内容它仍然能自适 ...

  3. Jenkins 自动化测试

    学习 Jenkins 自动化测试的系列文章 Robot Framework 概念 Robot Framework 安装 Pycharm + Robot Framework 环境搭建 Robot Fra ...

  4. linux源码学习-for_each_cpu

    刚开始读linux源码,第一眼就看到了这个很有意思的函数族,周末好好研究一下 3.13 这个组都是宏定义for循环,分析的时候注意到cpumask_next(),它在一个文件中定义了两次,还不是重载, ...

  5. 20135208JAVA第二次试验

    北京电子科技学院(BESTI) 实     验    报     告 课程:Java程序设计  班级:1352 姓名:贺邦  学号:20135208 成绩:             指导教师:娄嘉鹏  ...

  6. 团队目标WBS及具体任务分工

    • 首先我们讨论了实验第一个冲刺周期要实现的功能,我们的初期目标. •  然后我们进一步梳理了第一阶段的任务和需求. •  之后对任务进行了划分和领取. •  最后每个人对自己的任务进行了估算,并约定 ...

  7. HDU 5265 pog loves szh II 二分

    题目链接: hdu:http://acm.hdu.edu.cn/showproblem.php?pid=5265 bc(中文):http://bestcoder.hdu.edu.cn/contests ...

  8. C#中委托的理解

    请注意,这只是个人关于C#中委托的一点点理解,参考了一些博客,如有不周之处,请指出,谢谢! 委托是一种函数指针,委托是方法的抽象,方法是委托的实例.委托是C#语言的一道坎,明白了委托才能算是C#真正入 ...

  9. linux桌面使用鼠标中间健粘帖

    使用linux桌面很久了,一直习惯鼠标左键选中,右健弹出菜单复制粘帖. 没想到linux使用鼠标中间健粘帖,很方便. 参考:Linux鼠标中键复制粘贴之谜[Felix蛋疼科普贴] 用鼠标左键单击待复制 ...

  10. Windows下IntelliJ IDEA中调试Spark Standalone

    参考:http://dataknocker.github.io/2014/11/12/idea%E4%B8%8Adebug-spark-standalone/ 转载请注明来自:http://www.c ...