C++ note

主要是为了学习c++的类和对象

 

内容摘自 c++概述

http://see.xidian.edu.cn/cpp/biancheng/cpp/rumen_1/

 

1,变量 

,C++中,我们可以在函数体内声明一个静态局部变量(Static Local Variable)。它在函数运行结束后不会消失,并且只有声明它的函数中能够使用它。我们可以在函数体外声明一个变量,它称为全局变量(global variable),在某一层次声明的变量的作用域就终止于该变量所在层次的末尾。在某个函数的同一语法层次内不能声明多个名字相同的变量。在函数体内声明一个静态局部变量(Static Local Variable)。它在函数运行结束后不会消失,并且只有声明它的函数中能够使用它(static int a;)。

2,逻辑

if (m!=0 && n/m<1),当m=0时,电脑不会去尝试用n/m了,而是直接跳过整句语句。这样,我们就能够避免除数为零的错误了

“……?……:……”称为条件操作符,它的运算优先级比逻辑或还低,是目前为止优先级最低的操作符, max=(a>=b)?a:b;

在switch语句中,我们要记住四个关键词,分别是switch、case、default和break。

switch(表达式)

{

   case 常量表达式1:

   {

      语句块1;

      break;

   }

   default:

   {

      语句块n+1;

   }

}

cout <<setw(2) <<a <<b;语句中域宽设置仅对a有效,对b无效。

3,函数

一旦函数运行结束,那么该函数中声明的参数和变量都将消失。

return 符合返回值类型的表达式;

在返回空类型的函数中可以使用return语句,人为地停止函数的运行,也可以不使用return语句,使其运行完所有语句后自然停止。

4,存储

在定义默认参数时,必须在函数声明中定义

void create(int n=100);//在函数声明中定义默认参数

int size=sizeof(array)/sizeof(int);//数组的大小

数组作为参数传递给函数的只是数组首元素的地址,函数在需要用到后面元素时再按照这个地址和数组下标去查找

指针和整数C的加减法是指针向前或向后移动C个对应类型的存储区域

数组名是指针,但它是一个指针常量。也就是说,不带下标的数组名不能作为左值。

数组的大小在编译前必须是已知的常量表达式

不同于数组,结构是按值传递的。也就是说整个结构的内容都复制给了形参,即使某些成员数据是一个数组。使用返回结构体方式实现修改

5,调试

用函数声明和定义分离的方式:把所有的声明都放在shape.h中,把所有的定义放在shape.cpp中

#开头的命令都是编译预处理命令,比如#if、#else、#endif、#ifdef、#ifndef、#undef和#define

无论这个文件是C++提供的还是自己编写的,使用#include "文件名"命令一定是正确的

如果包含头文件时写作如#include <iostream>,但是没有using namespace std;必须要使用std名字空间。

在编译阶段发生的错误称为编译错误(Compile Error),在运行阶段发生的错误称为运行时错误(Runtime Error)。对于编译错误,我们通过检查并修正语法错误来解决;对于运行时错误,我们通过检查并修正语意(程序设计思想)错误来解决

6,对象

面向对象(Object Oriented,简称OO)

对象就是任何我们可以想象出来的具体的物体

能够抽象地描述某一些具有共性的物体的词称为类(Class)

类与结构相似,它也是一种由用户自己定义的数据类型;它也可以通过成员数据来刻画一些现实生活中的东西。不同的是,对它的操作并不是通过普通的函数,而是通过类的成员函数来实现的

定义完一个类之后务必要在最后加上一个分号。

类中变量在定义或声明时不说明该成员数据(或成员函数)是公有的还是私有的,则默认为私有的。

class Node//定义一个链表结点类

{

   public:

   int idata;//数据能够被外部访问

   char cdata;//数据能够被外部访问

   private:

   Node *prior;//前驱结点的存储位置保密

   Node *next;//后继结点的存储位置保密

};

如果一个类的某个成员函数是私有的,那么它只能被这个类的其他成员函数调用。

const这个保留字来保护成员数据不被成员函数改变

成员函数的写法就是在函数的参数表后面加上一个const,比如:int readi() const;//通过该函数读取idata,但不能改变任何成员数据

"::"操作符,它表示该函数是属于某一个类的,称为域解析操作符

定义类成员函数

//node.h

class Node//定义一个链表结点类

{

   public:

   int readi() const;//通过该函数读取idata,但不能改变任何成员数据

   bool set(int i);//重载,通过该函数修改idata

   bool set(char c);// 重载,通过该函数修改cdata

   private:

   int idata;//存储数据保密

   char cdata;//存储数据保密

};//类定义结束,分号切勿忘记

int Node::readi() const   //成员函数readi的定义

{

   return idata;

}

bool Node::set(int i)//重载成员函数定义

{

   idata=i;

   return true;

}

bool Node::set(char c)

{

   cdata=c;

   return true;

}

调用成员函数

//main.cpp

#include <iostream>

#include "node.h"//包含我们编写好的链表结点类头文件,必须用双引号

using namespace std;

int main()

{

   Node a;//创建一个链表结点对象a

   a.set(1);//设置idata

   a.set(‘A‘);//设置cdata

   cout <<a.readi() <<endl;

   cout <<a.readc() <<endl;

   return 0;

}

对象的引用

   Node b;//声明一个结点对象

   Node &a=b;//声明一个引用

   a.set(0);//效果与b.set(0)相同

对象指针

   Node b;//声明一个结点对象

   Node *a=&b;//声明一个对象指针

   a->set(0);//效果与b.set(0)相同

   a->readi();//效果与b.readi()相同

对象的初始化的方法,增加初始化函数 void init(type,type);

构造函数是一种随着对象创建而自动被调用的函数,与类同名的成员函数就是构造函数,它的主要用途是为对象作初始化,它是一个公有的成员函数,并且构造函数没有返回值类型。

class Node//定义一个链表结点类

{

   public:

   Node();//构造函数的声明,构造函数是公有的成员函数,没有返回值类型

   private:

   int idata;//存储数据保密

   char cdata;//存储数据保密

};

Node::Node() //构造函数的定义

{

   cout <<"Node constructor is running..." <<endl;//提示构造函数运行

   idata=0;//初始化idata

   cdata=‘0‘;//初始化cdata

}

带参数的构造函数(构造函数也可以重载)

Node::Node(int i,char c)//构造函数重载1,默认参数只需要在函数原型中出现

{

   cout <<"Node constructor is running..." <<endl;

   idata=i;

   cdata=c;

   prior=NULL;

   next=NULL;

}

 对应于main中的,Node b(8);//创建一个链表结点对象b,调用构造函数重载1,参数c默认为‘0‘

在C++中,每个类都有且必须有构造函数。如果用户没有自行编写构造函数,则C++自动提供一个无参数的构造函数,称为默认构造函数。这个默认构造函数不做任何初始化工作。一旦用户编写了构造函数,则这个无参数的默认构造函数就消失了。如果用户还希望能有一个无参数的构造函数,必须自行编写

深拷贝构造函数是真正意义上的复制了链表a,并且使得链表a和链表b各自独立,互不干扰。这才是自定义拷贝构造函数存在的重要意义

//拷贝构造  

 CExample(const CExample& C)  

 {  

  a = C.a;  

  cout<<"copy"<<endl;  

 }  

CExample B = A; // CExample B(A); 也是一样的,这里不是赋值

析构函数(Destructor)能随着对象的消亡而自动被调用

对象作为函数参数时,会先调用对象的拷贝构造函数,把参数的值复制给临时对象,函数结束后,临时对象调用析构函数

构造函数用于初始化对象,拷贝构造函数用于访问创建的对象,用于类向对象中的似有成员传递指

对象rect1的p和rect2的指针成员p各自指向一段内存空间,但它们指向的空间具有相同的内容,这就是所谓的“深拷贝”

初始式example

#include "iostream"

#include "stdlib.h"

using namespace std;

 

class A

{

public:

A(int i,char c);

void show();

private:

int idata;

char cdata;

};

A::A(int i,char c)

{

idata=i;

cdata=c;

}

void A::show()

{

cout <<"A.show"<<endl<<idata<<endl;

cout<<cdata<<endl;

cout<<"A.show end"<<endl;

}

class B

{

public:

B(int i,char c);

void show();

private:

int bint;

A ao;

A *p;

char bchar;

};

B::B(int i,char c):ao(i,c)

{

cout<<"B copy and creat"<<endl;

cout<<i<<c<<endl;

p=&ao;

cout<<"B copy and creat end"<<endl;

 }

void B::show()

{

cout<<"B.show begin"<<endl;

p->show();//或者ao.show();

cout<<"B.show end"<<endl;

}

int main()

{

A a(1,‘a‘);

a.show();

B b(2,‘b‘);

b.show();

system("pause");

}

如果指针指向不是用 new 分配的内存地址,则在该指针上使用 delete 是不合法的。

const int *pci = new const int(1024);

动态创建的 const 对象必须在创建时初始化,并且一经初始化,其值就不能再修改。

由new生成的ptemp,在执行delete之后,还可以对其进行赋值操作,猜想delete 操作删除的是指针指向内存的内容

 

一个类成员中有其他类对象,可以用以下方式构造(linklist成员中有node类,pucurrent和head分别为node类的对象和对象指针

方式一

Linklist::Linklist(int i,char c):head(i,c)//类名::构造函数名(参数表):成员对象名1(参数表),链表类构造函数,调用head对象的构造函数重载1,详见Node.h文件

{

   cout<<"Linklist constructor is running..."<<endl;

   pcurrent=&head;

}

方式二,需要在node类中声明linklist是友元类,friend class Linklist;

Linklist::Linklist(Linklist &l):head(l.head)

{

   cout<<"Linklist Deep cloner running..." <<endl;

   pcurrent=&head;

   Node * ptemp1=l.head.next;//直接访问私有成员数据

while(ptemp1!=NULL)//复制链表

   {

      Node * ptemp2=new Node(ptemp1->idata,ptemp1->cdata,pcurrent,NULL);

      pcurrent->next=ptemp2;

      pcurrent=pcurrent->next;

      ptemp1=ptemp1->next;

}

 

一个函数要访问一个或多个对象的私有成员时,我们可以用友元来解决这个问题。

friend void ShowNode(Node &n);//声明友元函数ShowNode,在节点类中声明

在main函数中可以使用ShowNode(b);//用友元函数输出b结点的内容

 

操作符重载,a是复数

void Complex::operator =(Complex a)

{

   real=a.real;

   img=a.img;

}

Complex Complex::operator +(Complex a)

{

   Complex temp(a.real+real,a.img+img);

   return temp;

}

这样在main函数中,可以进行操作

Complex a(3,2),b(5,4),c(1,1),d(4,2),temp;

   temp=a+b;

 

继承的方法,使我们可以用一种已经编写好的类来扩写成一个新的类

class 子类名:[public,private,protect]父类名;

private(私有)和protected(保护)都能实现类的封装性。private能够对外部和子类保密,即除了成员所在的类本身可以访问之外,别的都不能直接访问。protected能够对外部保密,但允许子类直接访问这些成员。

 

private是私有继承父类所有的公有、保护成员继承到子类时,类型会发生改变。父类的公有成员在子类中变成了私有成员,父类的保护成员在子类中也变成了私有成员。父类不能在访问子类中成员

 

class Stack:private Linklist//私有继承链表类

void Stack::show()

{

Show();//用Linklist类的成员函数实现功能

}

父类的成员对象是最先构造的,接着是运行父类的构造函数,最后运行子类的构造函数。

子类的构造函数的参数传递给父类的构造函数

Stack::Stack(int i,char c):Linklist(i,c)//将子类构造函数的参数传递给父类的构造函数

{

   cout <<"Stack constructor with parameter is running..." <<endl;

}

使用了继承之后,析构函数的运行顺序依然恰好与构造函数的运行顺序相反。

 

父类指针能否指向子类对象?子类指针能否指向父类对象?

在公有继承情况下父类的对象指针指向子类对象是允许的。子类的对象指针指向父类是禁止的

用父类的对象指针指向子类对象,那么这个指针无法使用子类中扩展出的成员。

 

子父类例子

如果有一个本科生对象s1和一个学生对象s2,那么显然s1.study()会是学习高等数学和大学英语,s2.study()会是随便学些什么。但是,如果有一个学生类的指针sp,它也能指向本科生对象,这时调用sp->study()会是怎么样的呢?我们发现,即使它指向一个本科生对象,它也只能“随便学些什么”。

 

不同的子类的同名成员函数有着不同的表现形式,称为多态性

多态性往往只有在使用对象指针或对象引用时才体现出来。多态性是面向对象的一个标志性特点,没有这个特点,就无法称为面向对象。

 

设置虚函数的方法为:在成员函数的声明最前面加上保留字virtual。注意,不能把virtual加到成员函数的定义之前,否则会导致编译错误。

 

virtual void study();//把学习设置为虚函数,父类中

void student::study()//成员函数定义处没有virtual

{

   cout <<"随便学些什么。" <<endl;

   return;

}

virtual void study();//把学习设置为虚函数,父类的一个子类中class Undergraduate:public student

void Undergraduate::study()//成员函数定义处没有virtual

{

   cout <<"学习高等数学和大学英语。" <<endl;

   return;

}

 virtual void study();//把学习设置为虚函数,父类的一个子类中class Pupil:public student

void Pupil::study()

{

   cout <<"学习语数外。" <<endl;

   return;

}

main函数中

 Undergraduate s1;

   student s2;

   Pupil s3;

student *sp

无论父类对象指针sp指向哪种子类对象,sp->study()的执行结果总是与对应的类相符合的

要使用虚函数实现多态性,至少要使各个函数的参数格式也完全相同。

当子类函数和父类参数不同时,会执行父类中的同名成员函数

编写成员函数的时候,可以把尽可能多的成员函数设置为虚函数。

 

给析构函数的前面加上保留字virtual, virtual ~Animal();//虚析构函数,父类animal中

子类中

Cat::~Cat()

{

   cout <<"Cat destructor is running..." <<endl;

}

main中

Animal *pa=new Cat(2,1);

   Cat *pc=new Cat(2,4);

delete pa;

   delete pc;

结果:

Cat constructor is running...

Animal consturctor is running...

Cat constructor is running...

Delete pa:

Cat destructor is running...

Animal destructor is running...

Delete pc:

Cat destructor is running...

Animal destructor is running...

子类和父类的析构函数都被执行

虚函数是为了实现多态,而虚析构函数是为了同时运行父类和子类的析构函数,使资源得以释放。

 

只能用于被继承而不能直接创建对象的类设置为抽象类(Abstract Class)。

类中的确存在,但是在父类中无法确定具体实现的成员函数称为纯虚函数。纯虚函数是一种特殊的虚函数,它只有声明,没有具体的定义。抽象类中至少存在一个纯虚函数;存在纯虚函数的类一定是抽象类。

 

设置纯虚函数之后并不影响多态的实现,但是却将父类变成了抽象类,限制了父类对象的创建,virtual void study()=0;//在父类的声明中通过代码实现,声明study为纯虚函数

 

C++ note,布布扣,bubuko.com

时间: 2024-10-15 14:53:55

C++ note的相关文章

383.判断一个字符串是否能够包含另外一个字符串 Ransom Note

Given an arbitrary ransom note string and another string containing letters from all the magazines, write a function that will return true if the ransom note can be constructed from the magazines ; otherwise, it will return false. Each letter in the

thinking in java ----reading note (1)

# thinking in java 4th# reading note# victor# 2016.02.10 chapter 1 对象入门 1.1 抽象的进步    (1) 所有东西都是对象.    (2) 程序是一大堆对象的组合,对象间通过消息联系.    (3) 通过封装现有对象,可制作出新型对象.    (4) 每个对象都有一种类型(某个类的实例).    (5) 同一类的所有对象都能接受相同的消息.    1.2 对象的接口 & 1.3 实现方法的隐藏     接口规定了可对一个特定

三星note手机上html5画面模糊解决方案

最近测试发现,html5游戏在三星note手机上初次加载都会模糊,刷新之后就不模糊了,不知道是什么原因,本人对底层的东西也不熟,后来问了个同事,找到个解决方案,现记录一下. <meta name="viewport" content="width=device-width,target-densitydpi=device-dpi,initial-scale=1.0,minimum-scale=1.0,maximum-scale=1.0,user-scalable=no&

Kali linux learning note

from:http://blog.sina.com.cn/s/blog_40983e5e0101dhz0.html 因为kali linux基于debian 7,当然要把这台Acer 4736z原有的debian 7删掉装kali啦,哈哈,这下不必为了BT5装虚拟机了,对于本子里60G的SSD来说还是好事一桩.要把kali当做桌面使用,就必须给kali添加一些软件,修改一些设置才好用,下面记录一下备忘,随时更新. 安装方法,官方文档,硬盘安装Kali Linux 把apt源设为官方提供的国内镜像

Beginning Scala study note(8) Scala Type System

1. Unified Type System Scala has a unified type system, enclosed by the type Any at the top of the hierarchy and the type Nothing at the bottom of the hierarchy. All Scala types inherit from Any. # Using Any, Book extends AnyRef, and x is an Int that

[Java Web]Error parsing HTTP request header Note: further occurrences of HTTP header parsing errors

手机客户端向服务器提交Http请求时,Tomcat抛出错误: 十二月 31, 2014 2:32:45 下午 org.apache.coyote.http11.AbstractHttp11Processor process信息: Error parsing HTTP request header Note: further occurrences of HTTP header parsing errors will be logged at DEBUG level. 经过调试后发现是Tomcat

configure: error: Cannot find libmysqlclient under /usr Note that the MySQL client library is not bundled anymore! 报错解决

错误说明 今天在centos 6.3 64位版本上安装PHP5.4.3时在./configure 步骤的时候出现了下面错误configure: error: Cannot find libmysqlclient under /usr.Note that the MySQL client library is not bundled anymore! 原因分析与解决 通过查找libmysqlclient,发现是在/usr/lib64/mysql/目录内的libmysqlclient.so.15.0

Note of sed

refers to <Linux Command Line and Shell Scripting Bible> date:Sep 17 2016 format for using sed command: set options script file command of 's',the s command substitutes a second text string for the first text string pattern specified between the for

由三星Note手机变砖后的一个想法

昨晚,很不幸,由于老旧的三星Note one 摔坏了Home键,不得不照网上的方法,用Re管理器修改系统文件,不想考虑不周结果重启后,怎么都没法进Android系统.今天询问一圈Mobile部门的同事,只有刷机,这样里面的个人数据就要丢失,有忘记做云备份.唉,心里那个不舒服啊,如果有个BaseOs该多好 这不,想到了Docker Container技术的BaseImage的技术,既然都是基于linux内核,那安卓手机照理也能搞啊,咨询了一下国外Linux系统的专家,这还真可以有.Android,

详细!交叉编译时 note: the mangling of &#39;va_list&#39; has changed in GCC 4.4解决办法

为什么要在标题前面加了详细两个字,就是为了吸引看文章的你还有写文章的我这种小白,我是从坑里面爬出来了. 废话少说.... 问题就是这样子了,至于解决办法,在网上搜索了很久,大多数以一段英文作为解决办法,... I think that the warning is accurate; the mangling of va_list has indeed changed on ARM in GCC 4.4 in order to conform to the ARM ABI specificati