C++学习笔记(类和对象)
实现一个复数类,类的定义和使用,C++2016-07-03
相信大家都明白C++是面向对象的语言(C++不是纯的面向对象的语言,是基于面向对象的语言(C++包含面向过程的语言C语言)),那仫什仫是面向对象呢?
要理解面向对象首先就要理解什仫是对象.
对象:在现实世界中任何事物都是对象,它可以是具体的,有形的,也可以是无形的,抽象的, 比如香蕉,橘子,苹果,卡车,汽车...这些具体的事物,再比如一场比赛,一场电影...这些抽象的事物,地球上的万事万物都可以是对象而我们把具有相同属性的对象统称为类(类是对象的抽象,对象是类的实例)
看到这里我们大概对什仫是类有了更加深入的理解,那仫在C++中的类是什仫样子呢?它有什仫规律呢?
下面我们先来看一个关于日期类的功能实现代码:
#include<iostream> using namespace std; class Data { public: //Data(); //不带参的构造函数 Data(int y=2017,int m=1,int d=1); //带参的构造函数 void print(); private: int year; int month; int day; }; Data::Data(int y,int m,int d) //全缺省 { year=y; month=m; day=d; } void Data::print() { cout<<year<<"-"<<month<<"-"<<day<<endl; } int main() { Data d1; Data d2(2016,7,3); d1.print(); d2.print(); return 0; }
@类的构成:数据成员,成员函数
1. 类中如果没有限定符,则数据成员默认是私有的(private),成员函数默认是共有的(public)
2.类的定义与结构体类似,不同之处在于:如果结构体和类都没有限定符,结构体中默认是共有的(public),类中默认是私有的(private)
3.可以在类内定义成员函数也可以在类外定义成员函数,比如上述代码就是在类外定义成员函数的
@类的访问限定符:public,private,protected
1.public可以从类外部直接访问,private/protected不能从类外部直接访问
2.每个限定符在一个类中可以使用多次,它的作用域从该限定符出现到下一个限定符之前或类体结束前
3.类的访问权限体现了类的封装性
4.protected:称为类的保护部分,用它来修饰的话:成员可以由该类和该类的派生类的成员函数来访问,类外是无法访问的(此限定符到学到继承时再详细理解)
@类的作用域
在C++的作用域分类中,除了C和C++共有的局部域和全局域之外还有C++特有的类域和名字空间域:
类域(类的作用域)
1.在类外定义成员需要使用::(作用域解析符)来指明属于哪一个类
2.访问方式与结构体类似,对象可以通过.直接访问数据成员,指向对象的指针可以通过->来访问类中的成员
3.类的成员都在类的作用域内,成员函数可任意访问成员变量和其他成员函数
@隐含的this指针
1.this指针是成员函数的隐含指针形参,我们不能在成员函数的形参中添加this指针的参数定义,也不能在调用时显示this指针
2.在对象调用成员函数时,对象地址作为实参传递给成员函数的第一个指针形参this指针
3.每个成员函数都有一个指针形参,是隐含的(构造函数比较特殊没有这个隐含的this指针)
在上述代码中调用print函数时就传过来的是隐含的this指针,具体分析见下图:
@构造函数
在上述Data类中有两个函数Data(int y,int m,int d);和Data(),这两个函数就是构造函数(用于给类的数据成员初始化)
构造函数的特点:(构造函数就是特殊的成员函数)
1.函数名与类名相同
2.构造函数是没有返回值也没有类型的,在定义构造函数时,是不能说明构造函数的类型的,甚至定义为void也不行,没有类型不等于类型为空.
3.如果类中没有定义构造函数,则C++编译器会自动产生一个缺省的构造函数,如果定义了就使用这个定义的构造函数
4.构造函数可以重载,比如在上述代码中定义了两个构造函数Data
5.构造函数也和普通的成员函数类似,即可以在类内定义也可以在类外定义
6.对象实例化时自动调用对应的构造函数
7.无参的构造函数和全缺省的构造函数都是缺省的构造函数,并且缺省的构造函数只能有一个;在上述代码中如果在带参数的构造函数的声明中使用全缺省的定义方式时编译器会报错,因为如果你给类实例化时是如果是不带参的而且构造函数是可以重载的,此时会产生调用不明确的情况
@析构函数
析构函数:是一种特殊的成员函数,通常用于回收或者清理资源,它的特点如下:
1.析构函数在类名上加上字符~
2.析构函数无参数也无返回值,类似构造函数
3.唯一性:一个类有且只有一个析构函数
4.析构函数不是删除对象而是清理
5.当程序执行到return 0;快要结束时系统自动调用析构函数
@运算符重载
为了支持程序的可读性,C++支持运算符重载,那仫什仫是运算符重载的特点呢?下面让我们先来看一道简单的运算符重载的例子(它的作用是将简单的加法运算输出结果两个数为相减的结果):
#include<iostream> using namespace std; class Int { public: Int(int d=0) //全缺省的构造函数 { _data = d; } Int operator+(Int m) { return Int(_data - m._data); } public: int _data; }; int main() { Int a(3); Int b(5); Int c = a+b; cout<<c._data<<endl; return 0; }
由上述代码总结出一下几个运算符重载的特征:
1.赋值运算符的重载是对一个已经存在的对象进行复制
2.运算符重载不改变运算符的优先级/结合性/操作符个数
3.几个C++不能重载的运算符: .* (点乘) / ::(作用域解析符) / sizeof / ?:(条件运算符) / .
下面穿插一个小代码就是用运算符重载来实现复数的运算"加,减,乘,除,加等,减等,乘等,除等"操作 :
#include<iostream> using namespace std; class Complex { public: Complex(double r,double i); Complex operator+(Complex &c); Complex operator-(Complex &c); Complex operator*(Complex &c); Complex operator/(Complex &c); Complex operator+=(Complex &c); Complex operator-=(Complex &c); Complex operator*=(Complex &c); Complex operator/=(Complex &c); void print(Complex c); private: double real; double image; }; Complex::Complex(double r=0.0, double i=0.0) { real=r; image=i; } Complex Complex::operator+(Complex &c) { double r=real+c.real; double i=image+c.image; return Complex(r,i); } Complex Complex::operator-(Complex &c) { double i=real-c.real; double r=image-c.image; return Complex(r,i); } Complex Complex::operator*(Complex &c) { double r=real*c.real-image*c.image; double i=image*c.real+real*c.image; return Complex(r,i); } Complex Complex::operator/(Complex &c) { double demo=c.real*c.real+c.image+c.image; double r=real*c.real-image*(-c.image); double i=image*c.real+real*(-c.image); return Complex(r/demo,i/demo); } Complex Complex::operator+=(Complex &c) { real=real+c.real; image=image+c.image; return Complex(real,image); } Complex Complex::operator-=(Complex &c) { real=real-c.real; image=image-c.image; return Complex(real,image); } Complex Complex::operator*=(Complex &c) { double r=real; //防止在后面求新的实部和虚部时被覆盖 double i=image; real=r*c.real-i*c.image; image=i*c.real+r*c.image; return Complex(real,image); } Complex Complex::operator/=(Complex &c) { double r=real; double i=image; double demo=c.real*c.real+c.image+c.image; real=r*c.real-i*(-c.image); image=i*c.real+r*(-c.image); return Complex(real/demo,image/demo); } void Complex::print(Complex c) { cout<<c.real<<" "<<c.image<<endl; } int main() { Complex c1(3.0,4.0); Complex c2(1.0,2.0); Complex *c=NULL; c->print(c1); c->print(c2); cout<<"c1+c2:"; c->print(c1+c2); cout<<"c1-c2:"; c->print(c1-c2); cout<<"c1*c2:"; c->print(c1*c2); cout<<"c1/c2:"; c->print(c1/c2); //cout<<"c1+=c2:"; //c->print(c1+=c2); //cout<<"c1-=c2:"; //c->print(c1-=c2); //cout<<"c1*=c2:"; //c->print(c1*=c2); cout<<"c1/=c2:"; c->print(c1/=c2); system("pause"); return 0; }
总结的不太全面,嘿嘿...