主要是为了学习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为纯虚函数
完
- 三星Note 7停产,原来是吃了流程的亏
三星Note 7发售两个月即成为全球噩梦,从首炸到传言停产仅仅47天.所谓"屋漏偏逢连天雨",相比华为.小米等品牌对其全球市场的挤压.侵蚀,Galaxy Note 7爆炸事件这场连 ...
- 《Note --- Unreal --- MemPro (CONTINUE... ...)》
Mem pro 是一个主要集成内存泄露检测的工具,其具有自身的源码和GUI,在GUI中利用"Launch" button进行加载自己待检测的application,目前支持的平台为 ...
- 《Note --- Unreal 4 --- Sample analyze --- StrategyGame(continue...)》
---------------------------------------------------------------------------------------------------- ...
- [LeetCode] Ransom Note 赎金条
Given
an
arbitrary
ransom
note
string
and
another
string
containing
letters from
all
th ...
- Beginning Scala study note(9) Scala and Java Interoperability
1. Translating Java Classes to Scala Classes Example 1: # a class declaration in Java public class B ...
- 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 h ...
- Beginning Scala study note(7) Trait
A trait provides code reusability in Scala by encapsulating method and state and then offing possibi ...
- Beginning Scala study note(6) Scala Collections
Scala's object-oriented collections support mutable and immutable type hierarchies. Also support fun ...
- Beginning Scala study note(5) Pattern Matching
The basic functional cornerstones of Scala: immutable data types, passing of functions as parameters ...
- Beginning Scala study note(4) Functional Programming in Scala
1. Functional programming treats computation as the evaluation of mathematical and avoids state and ...
随机推荐
- 采用HSV生成随机颜色
使用hsv/hsb生成随机颜色,并排除靠近黑白两色的色值 public static String randomColor(){ int max = 25500000 ; Random rand = ...
- 【FFXV】中物理模拟的结构以及游戏业界的乐趣
11月2日是在日本兵库县神户会议中心召开的[SIGGRAPH ASIA 2015]的第一天,在游戏开发专门的研究会[R&D in the Video Game Industry]上,展开了[F ...
- #define与运算精度问题探究
#include <stdio.h> #define SQR(X) X*X int main(int argc, char* argv[]) { ; ; ; printf("SQ ...
- libopencv_highgui.a(window_gtk.cpp.o): undefined reference to symbol 'g_type_check_instance_is_a'
libopencv_highgui.a(window_gtk.cpp.o): undefined reference to symbol 'g_type_check_instance_is_a' 尝试 ...
- 国外it网站收集
1.http://news.com.com/2.http://www.zdnet.com/3.http://www.salon.com/tech/index.html4.http://www.brin ...
- Visual Mingw
Visual-MinGW 是一个专门为MinGW所设计的IDE.如果,你曾经用过VC++ 6.0这个IDE,你的第一感觉就是,Visual-MinGW和VC++ 6.0非常相似.所以,对于曾经用惯VC ...
- delphi android 录像(调用Java的功能)
delphi xe系列自带的控件都无法保存录像,经网友帮忙,昨天终于实现了录像功能(但有个问题是录像时无画面显示),程序主要使用了JMediaRecorder,MediaRecorder的使用方法可参 ...
- git中应用在vs中使用gitignore (转)
在进行协作开发代码管理的过程中,常常会遇到某些临时文件.配置文件.或者生成文件等,这些文件由于不同的开发端会不一样,如果使用git add . 将所有文件纳入git库中,那么会出现频繁的改动和push ...
- C#中Attribute介绍
什么是特性? MSDN中定义为:公共语言运行时运行添加类似关键字的描述声明,叫做Attribute,它对程序中的元素进行标注,如类型.方法.字段和属性等.attribute和Microsoft.Net ...
- 转:Asp.net Mvc4默认权限详细(上)
前言 上篇的菜鸟去重复之Sql的问题还没有得到满意的答案.如果哪位大哥有相关的资料解释,能够分享给我,那就太谢谢了. 以后每发表一篇博文我都会将以前遗留的问题在前言里指出,直到解决为止. 本文主要在于 ...