C++学习笔记(6)
面向对象编程:
1.对象和类
(1)声明类: 类定义了对象的属性和行为。
一个对象的状态: 用数据域以及他们的当前值来表示。
一个对象的行为,由一组函数确定。
所以在c++类中,用变量定义数据域,用函数来定义行为
(2)定义类和创建对象:
定义一个圆的类:
#include <iostream>
using namespace std;
class Circle
{
public:
double radius;
// constructor
Circle()
{
radius = 1.0;
}
// 构造方法
Circle(double new_radius)
{
radius = new_radius;
}
// 函数
double getArea()
{
return 3.14 * radius * radius;
}
}; // 这里要写分号
int main(int argc, char *argv[])
{
Circle circle1;
Circle circle2(12.5);
Circle circle3(123);
cout << "radius of circle 1 is " << circle1.radius << endl;
cout << "Area of circle 3 is " << circle3.getArea() << endl;
return 0;
}
public关键字:表示所有的数据域,构造函数和普通成员函数都可以通过类对象来访问。如果不用关键字public,那么这些成员的可见性缺省为private
了解UML图(Unified Modelling Language)统一建模语言描述
简单程序:定义一个电视TV的类,包括频道切换,开关机,音量调节
#include <iostream>
using namespace std;
class TV
{
public:
int channel;
int volume_level;
bool on;
//定义构造方法
TV()
{
channel = 1;
volume_level = 40;
on = false;
}
void turnOn()
{
on = true;
}
void turnOff()
{
on = false;
}
void setChannel(int new_channel)
{
if(on && new_channel >=1 && new_channel<=120)
{
channel = new_channel;
}
}
void setVolume(int volume)
{
if(on && volume>=0 && volume<=100)
{
volume_level = volume;
}
}
void channelUp()
{
if(on && channel<120)
channel++;
}
void channelDowm()
{
if(on && channel>0)
channel--;
}
void volumeUp()
{
if(on && volume_level<100)
volume_level++;
}
void volumeDown()
{
if(on && volume_level>0)
volume_level--;
}
};
int main(int argc, char *argv[])
{
TV tv1;
cout << "The state of tv is " << tv1.on << endl;
cout << "The channel is " << tv1.channel << endl;
cout << "The volume is " << tv1.volume_level << endl;
tv1.turnOn();
tv1.setChannel(56);
tv1.setVolume(60);
cout << "The state of tv is " << tv1.on << endl;
cout << "The channel is " << tv1.channel << endl;
cout << "The volume is " << tv1.volume_level << endl;
tv1.channelUp();
tv1.volumeDown();
cout << "The state of tv is " << tv1.on << endl;
cout << "The channel is " << tv1.channel << endl;
cout << "The volume is " << tv1.volume_level << endl;
return 0;
}
2.构造函数
构造函数可以理解为一种特殊的函数,与普通的函数相比,主要不同点有:
1.构造函数的名字必须与类的名字相同
2.构造函数没有返回类型 返回void也不可以
3.创建对象时,构造函数被调用, 他的作用就是初始化对象
构造函数也可以重载(可以同名,但函数签名不同),构造函数用来初始化数据域。
注: 类中的变量作为类的新成员,在声明时不能进行初始化。比如Circle类里面的radius,在声明不能初始化,只能在构造方法中为其赋值。
3.创建及使用对象
对象创建后,可以通过.运算(即对象成员访问运算符)来访问对象的数据以及调用对象的函数
尽量将类名的每个单词首字母大写
“=”可以进行两个对象之间内容的复制,但他们仍然是两个不同的对象
@@,一个对象包含的数据存储在内存里,但是函数并不需要存储,因为函数是这个类所有对象共享的,编译器仅仅创建一份拷贝就可以了。例如对于circle1, circle2,他们的大小都是一个double类型所占的字节的大小。
@@有时创建一个对象,但只需要使用一次,这时无需为对象命名,创建为匿名对象即可
3.类定义和类实现的分离
分离类定义和类实现有利于类的维护。
使用类的程序称为客户程序。
::称为二元作用域解析运算符,指明类成员的作用范围。
分离的好处:
1.可以实现隐藏。在不改变类的定义的前提下,可以自由修改类的实现
2.作为软件供应商,只要提供类定义的文件和类实现的目标代码,从而隐藏了类实现的源代码,保护软件上的知识产产权
类定义放在h文件中,类实现在.cpp文件中
.h文件中类的定义
// 关于类的定义
class Circle
{
public:
// 定义数据域
double radius;
// 构建函数
Circle();
// 构建函数
Circle(double);
// 定义函数
double getArea();
}
.cpp文件中类的实现
#include "E:\back_up\code\c_plus_code\chapter10\external_file\circle.h"
Circle::Circle()
{
radius = 1.0;
}
Circle::Circle(double new_radius)
{
radius = new_radius;
}
double Circle::getArea()
{
return 3.14*radius*radius;
}
在main.cpp中调用:
#include <iostream>
#include "E:\back_up\code\c_plus_code\chapter10\external_file\circle.h"
using namespace std;
int main(int argc, char *argv[])
{
Circle c1;
Circle c2(5);
cout << "The radius of c1 is " << c1.radius << endl;
cout << "The area of c1 is " << c1.getArea() << endl;
cout << "The radius of c2 is " << c2.radius << endl;
cout << "The area of c2 is " << c2.getArea() << endl;
return 0;
}
注: include 应该包含circle.h的完整路径,否则会报错
4.避免多次包含
Head.h文件
#include circle.h
Test.cpp文件:
#include circle.h
#include head.h
在上面的代码中,circle.h被重复包含,编译器会报错
如何解决在一个程序中多次包含相同的头文件。如果多次包含,C++编译器会报错,因为预处理器会把#include后的内容直接插入到他们被包含的位置,如果重复包含,就相当于重复插入了相同的内容,就会出现类有多个定义的报错。
包含保护: 原语句 #ifndef和#define可以避免头文件多次被包含,所以在头文件中应该包含。
// 关于类的定义
#ifndef CIRCLE_H
#define CIRCLE_H
class Circle
{
public:
// 定义数据域
double radius;
// 构建函数
Circle();
// 构建函数
Circle(double);
// 定义函数
double getArea();
} ;
#endif
先测试CIRCLE_H是否已经定义,如果没有,则定义,并且把头文件的其他部分也包含进来,否则跳过、
5. 数据域封装
数据域私有可以保护数据,使类便于维护。
例如,对于类Circle,要防止客户程序直接修改radius的值,以防止客户程序直接修改类的属性,因此,使用关键字private,将数据域设为私有,这就是数据域封装。
一个私有的程序,无法通过直接引用类对象来访问它。 如果需要访问,需改,需要定义一个get()函数和一个set()函数,即访问器(accessor)和更改器(mutator)
Circle类:
circle.h文件
// 关于类的定义
#ifndef CIRCLE_H
#define CIRCLE_H
class Circle
{
private: // 数据域封装
double radius;
public:
// 定义数据域
//double radius;
// 构建函数
Circle();
// 构建函数
Circle(double);
// 定义函数
double getArea();
// define accessor
double getRadius();
// define mutator
void setRadius(double);
} ;
#endif
circle.cpp文件
// 类的实现
#include "E:\back_up\code\c_plus_code\chapter10\external_file\circle.h"
Circle::Circle()
{
radius = 1.0;
}
Circle::Circle(double new_radius)
{
radius = new_radius;
}
double Circle::getArea()
{
return 3.14*radius*radius;
}
double Circle::getRadius() // 访问器
{
return radius;
}
void Circle::setRadius(double new_radius) // 更改器
{
radius = (new_radius>=0) ? new_radius : 0; //语法糖
}
客户端程序:
#include <iostream>
#include "E:\back_up\code\c_plus_code\chapter10\external_file\circle.h"
using namespace std;
int main(int argc, char *argv[])
{
//Circle c1;
Circle c2(5);
cout << "The radius of c2 is " << c2.getRadius() << endl;
cout << "The area of c2 is " << c2.getArea() << endl;
c2.setRadius(10.5);
cout << "The radius of c2 is " << c2.getRadius() << endl;
cout << "The area of c2 is " << c2.getArea() << endl;
return 0;
}
6.变量作用域
全局变量
局部变量
局部静态变量
在类中,数据域被定义为便变量的形式,可以被所有成员函数访问
在类中,如果一个局部变量和一个数据域有相同的名字,数据域将被覆盖,局部变量的优先级是最高的
7.类的抽象和封装
银行获取贷款的例子:
Loan:
数据域: 利率, 贷款额度, 贷款年限 (用private实现类的封装)
构造方法: Loan()以及Loan(int, double , double)
函数:
year(access, mutator),
loan_amount(access, mutator)
interest_rate(access, mutator)
getMonthlyPayment()
getTotalPayment()
代码:
Loan.h文件:
// loan的定义
#ifndef LOAN_H
#define LOAN_H
class Loan
{
public:
// 构造方法
Loan();
Loan(int year, double loan_amount, double year_interest_rate);
int getYear(); // accessor for year
void setYear(int); // mutator for year
double getYearInterestRate(); // accessor for interest rate
void setYearInterestRate(double); // mutator for interest rate
double getLoanAmount(); // access for LoanAmount
void setLoanAmount(double); //mutator for
double getMonthPayment();
double getTotalPayment();
private:
int years;
double loan_amounmt;
double year_interest_rate;
//double month_payment;
//double total_payment;
};
#endif
Loan.cpp文件:
// 类的实现
#include "E:\back_up\code\c_plus_code\chapter10\external_file\loan.h"
#include <cmath>
Loan::Loan()
{
years = 5;
loan_amounmt = 100000;
year_interest_rate = 4;
}
Loan::Loan(int year, double amounmt, double rate) // 在类的实现中,参数的名字不能与变量的名字相同
{
years = year;
loan_amounmt = amounmt;
year_interest_rate = rate;
}
int Loan::getYear()
{
return years;
}
void Loan::setYear(int year)
{
years = year;
}
double Loan::getYearInterestRate()
{
return year_interest_rate;
}
void Loan::setYearInterestRate(double rate)
{
year_interest_rate = rate;
}
double Loan::getLoanAmount()
{
return loan_amounmt;
}
void Loan::setLoanAmount(double amounmt)
{
loan_amounmt = amounmt;
}
double Loan::getMonthPayment()
{
double month_interest_rate = year_interest_rate / 1200;
return loan_amounmt * month_interest_rate / (1 - pow(1 / (1+month_interest_rate), years * 12));
}
double Loan::getTotalPayment()
{
return getMonthPayment() * 12 * years;
}
注:在类的实现中函数参数的命名与类中的数据域命名应该不一样,否则会有错误(程序不报错,但会出现错误的结果)
用户程序:
#include <iostream>
#include "E:\back_up\code\c_plus_code\chapter10\external_file\circle.h"
#include "E:\back_up\code\c_plus_code\chapter10\external_file\loan.h"
using namespace std;
int main(int argc, char *argv[])
{
Loan loan_1;
cout << "The year is " << loan_1.getYear() << endl;
cout << "loan amount is " << loan_1.getLoanAmount() << endl;
cout << "loan rate is " << loan_1.getYearInterestRate() << endl;
cout << "month payment is " << loan_1.getMonthPayment() << endl;
cout << "total payment is " << loan_1.getTotalPayment() << endl;
loan_1.setYear(10);
loan_1.setYearInterestRate(8.5);
loan_1.setLoanAmount(80000);
cout << "-----------------------------" << endl;
cout << "The year is " << loan_1.getYear() << endl;
cout << "loan amount is " << loan_1.getLoanAmount() << endl;
cout << "loan rate is " << loan_1.getYearInterestRate() << endl;
cout << "month payment is " << loan_1.getMonthPayment() << endl;
cout << "total payment is " << loan_1.getTotalPayment() << endl;
Loan loan_2(15, 30000, 6.4);
cout << "-----------------------------" << endl;
cout << "The year is " << loan_2.getYear() << endl;
cout << "loan amount is " << loan_2.getLoanAmount() << endl;
cout << "loan rate is " << loan_2.getYearInterestRate() << endl;
cout << "month payment is " << loan_2.getMonthPayment() << endl;
cout << "total payment is " << loan_2.getTotalPayment() << endl;
return 0;
}