目录
类和对象上篇
封装 对象
#include<iostream>
#include<string>
using namespace std;
//类和对象:
//c++面向对象的三大特征:封装、继承、多态
//c++认为万事万物都皆为对象,对象上有其属性和行为
//例如:人可以作为对象,属性有姓名、年龄、身高、体重、、、
//行为有走、跑、跳、吃饭、唱歌、、、
//封装:
//封装的意义:
//将属性和行为作为一个整体、表现生活中的事物
//将属性和行为加以权限控制
//语法 class 类别 {访问权限:属性 / 行为};
//设计一个圆类,求圆的周长
//访问权限:
//public 公共权限 成员 类内可以访问 类外可以访问
//protected 保护权限 成员 类内可以访问 类外不可以访问 儿子可以访问父亲中的保护内容
//private 私有权限 成员 类内可以访问 类外不可以访问 儿子不可以访问父亲的私有内容
//struct和class区别
//在c++中struct和class唯一区别就在于默认的访问权限不同
//区别:
//struct默认权限为公共
struct c1{
int a;//默认权限是公共
};
//class 默认权限为私有
class c2{
int a;
};
// 成员属性设置为私有
// 优点1:将所有成员属性设置为私有,可以自己控制读写权限
// 优点2:对于写权限,我们可以检测数据有效性
// 将所有成员属性设置为私有,可以自己控制读写权限
class person1
{
public:
//设置姓名
void setname(string name){
m_name = name;
}
string getname(){
return m_name;
}
void setage(int age){
if(age < 0 || age>150){//对于写权限,我们可以检测数据有效性
cout<<"年龄输入有误,赋值失败"<<endl;
return;
}
m_age = age;
}
int getage(){
return m_age;
}
string setidol(string idol){
m_idol =idol;
}
private:
//姓名
string m_name; //可读 可写
//年龄
int m_age ; // 只读 也可写(年龄必须在0-150之间)
//偶像
string m_idol; // 只写
};
// 对象的初始化和清理:
// c++中的面向对象来源于生活,每个对象也都会有初始化设置以及对象销毁前的清理数据的设置
// 构造函数和析构函数
// 如果我们不提构造和析构,编译器会提供。但是编译器提供的构造函数和析构函数是空实现
// 构造函数由编译器自动调用,无须手动调用
//构造函数:主要作用在于构建对象时为对象的成员属性赋值,
//语法:类名(){}
//1.构造函数,没有返回值也不写void
//2.函数名称和类名相同
//3.构造函数可以有参数因此可以发生重载
//4.程序在调用对象的时候会自动调用构造,无须手动调用,而且只会调用一次
// 析构函数:主要作用在于对象销毁前系统自动调用,执行一些清理工作
//语法:~类名(){}
//1.析构函数,没有返回值也不写void
//2.函数名称与类名相同,在名称前加入符号~
//3.析构函数不可以有参数,因此不可以发生重载
//4.程序在对象销毁前会自动调用析构,无须手动调用,而且只会调用一次
class person2{
//构造函数:主要作用在于构建对象时为对象的成员属性赋值,
//语法:类名(){}
//1.构造函数,没有返回值也不写void
//2.函数名称和类名相同
//3.构造函数可以有参数因此可以发生重载
//4.程序在调用对象的时候会自动调用构造,无须手动调用,而且只会调用一次
public:
person2(){
cout<<"person2 无参构造函数的调用"<<endl;
}
person2(int a){
age=a;
cout<<"person2 有参构造函数的调用"<<endl;
}
person2(const person2 &p){
age=p.age;
cout<<"person2 拷贝构造函数的调用"<<endl;
}
//析构函数:
//语法:~类名(){}
//1.析构函数,没有返回值也不写void
//2.函数名称与类名相同,在名称前加入符号~
//3.析构函数不可以有参数,因此不可以发生重载
//4.程序在对象销毁前会自动调用析构,无须手动调用,而且只会调用一次
~person2(){
cout<<"person2 析构函数的调用"<<endl;
}
public:
int age;
};
//构造函数的分类及调用
//两种分类方法
//按参数分为:有参和无参构造
/*class person2{
person2(){
cout<<"person2 无参构造函数的调用"<<endl;
}
person2(int a){
cout<<"person2 有参构造函数的调用"<<endl;
}
}; */
//按类型分为:普通类型和拷贝构造
/*person(const person &p){
//将传入的人身上的所有属性,拷贝到我身上
age=p.age;
}*/
//三种调用方法:
//括号法,显示法,隐式转换法
//拷贝构造函数调用时机
//1.使用一个已经创建完毕的对象来初始化一个新对象
//person2 p2(p1);//拷贝构造
//2.值传递的方法给函数参数传值
/*
viod work(person2 p){
}
work(p);
*/
//3.以值方式返回局部对象
/*
person work1(){
person p;
retrun p;
}
person p = work1();
*/
//构造函数调用规则
//默认情况下,c++编译器至少给一个类添加三个函数
//1.默认构造函数(无参,函数体为空)
//2.默认析构函数(无参,函数体为空)
//3.默认拷贝函数,对属性进行值拷贝
//如果用户定义有参构造函数,c++不在提供默认无参构造,但是会提供默认拷贝构造
//如果用户定义拷贝构造函数,c++不会再提供其他构造函数
void test(){
person2 p3;//在栈上的数据,test执行完毕之后就会释放
}
void test1(){
//括号法调用 不能 person2 p();这样写
person2 p;//无参构造
person2 p1(10);//有参构造
person2 p2(p1);//拷贝构造
cout<<"p1 的年龄"<<p1.age<<endl;
cout<<"p2 的年龄"<<p2.age<<endl;
}
void test2(){
//显试法调用
person2 p;//无参构造
person2 p1=person2(10);//有参构造
person2 p2=person2(p1);//拷贝构造
// person(10);//匿名对象 特点:当前行执行结束后,系统会立即回收掉匿名对象
// 不要利用拷贝构造函数 初始化匿名对象 编译器会认为person(p3) = person p3;
cout<<"p1 的年龄"<<p1.age<<endl;
cout<<"p2 的年龄"<<p2.age<<endl;
}
void test3(){
//隐式转换法调用
person2 p;//无参构造
person2 p1=10;//有参构造 相当于写了person2 p1 = person(10);
person2 p2=p1;//拷贝构造
cout<<"p1 的年龄"<<p1.age<<endl;
cout<<"p2 的年龄"<<p2.age<<endl;
}
class person{
//公共权限
public:
string name;
//保护权限
protected:
string car;
//私有权限
private:
int passward;
public:
void func(){
name = "张三";
car = "拖拉机";
passward = 123456;
}
};
const double pi = 3.14;
class circle{
//类中的属性和行为 我们统一称为行为
//属性 (成员属性=成员变量)
//行为 (成员函数=成员方法)
//访问权限
public://公共权限
//属性
int r;//半径
//行为
double calculateZC(){
return 2*pi*r;
} //获取圆的周长
};
//设计一个学生类,属性有姓名和学号,可以给姓名和学号赋值,可以显示学生的姓名和学号
class student{
public:
string name;
string id;
void show(){
cout<<"姓名:"<<name<<"\t学号:"<<id<<endl;
}
};
int main(){
//通过圆类 创建具体的圆(对象)
//实例化 (通过一个类 创建一个对象的过程)
circle cl;
//给圆对象 的属性进行赋值
cl.r = 10;
cout<<"圆的周长为:"<<cl.calculateZC()<<endl;
//通过学生类 创建具体的学生(对象)
student s1;
//给学生对象 的属性进行赋值
s1.name="小张";
s1.id="001";
s1.show();
person p1;
p1.name = "李四";
//p1.car = "宝马"; 类外不能访问
p1.func();
c1 c1;
c2 c2;
c1.a =100;
//c2.a =100; //权限为私有不能被访问
person1 p2;
//姓名设置
p2.setname("张三");
//姓名读取
cout<<"姓名:"<<p2.getname()<<endl;
//年龄设置 对于写权限,我们可以检测数据有效性
p2.setage(160);
p2.setage(18);
//年龄读取
cout<<"年龄:"<<p2.getage()<<endl;
//偶像写入
//p2.setidol("冠宇");
//对象的初始化和清理
//1、构造函数,进行初始化操作
test();//自动调用
//2、析构函数
person2 p3;//在释放程序那一刻会执行析构函数
test1(); //括号法
test2(); //显试法
test3(); //隐式转化法
system("pause");
return 0;
}
对象、友元
#include<iostream>
#include<string>
using namespace std;
//浅拷贝和深拷贝
//如果属性有在堆区开辟,一定要自己提供拷贝构造函数防止浅拷贝带来的问题
class person{
public:
person(){
cout<<"person的默认构造函数调用"<<endl;
}
person(int age,int height){
cout<<"person的有参函数调用"<<endl;
m_height = new int(height);//new开辟一个空间在堆区 ,返回的是int *
m_age = age;
}
~person(){
//堆区开辟的数据由程序员手动开辟,手动释放
if(m_height != NULL){
delete m_height;
m_height = NULL;
}
//会出现运行错误
//person p2(p1)
//如果利用编译器提供的拷贝构造函数,会做浅拷贝操作
//p2和p1会重复释放堆区的内存,浅拷贝带来的问题就是堆区的内存重复释放
//需要自己写拷贝函数,深拷贝
cout<<"person的析构函数调用"<<endl;
}
person(const person &p){
cout<<"拷贝函数的调用"<<endl;
m_age = p.m_age;
//m_height = p.m_height;//编译器默认就是这行代码
//深拷贝操作
m_height = new int(*p.m_height);
}
int m_age;
int *m_height;
};
void test(){
person p1(50,160);
person p2(p1);
cout<<"p1的年龄为:"<<p1.m_age<<"\tp1的身高为:"<<*p1.m_height<<endl;
cout<<"p2的年龄为:"<<p2.m_age<<"\tp2的身高为:"<<*p2.m_height<<endl;
}
//初始化列表
class person1
{
public:
//传统初始化
// person1(int a,int b,int c){
// m_a = a;
// m_b = b;
// m_c = c;
// }
//初始化列表初始化属性
person1(int a,int b,int c):m_a(a),m_b(b),m_c(c)
{
}
int m_a,m_b,m_c;
};
void test1(){
//person1 p3(10,20,30); 传统初始化
person1 p3(10,20,30); //初始化列表赋值
cout<<"m_a= "<<p3.m_a<<endl;
}
//类对象作为类成员
//当其他类对象作为本类成员,构造时候先构造类对象,再构造自身,
//析构先释放自身,再释放类对象
//手机
class phone{
public:
phone(string pname){
m_pname = pname;
}
//手机名称
string m_pname;
};
//人类
class person2
{
public:
person2(string name, string pname):m_name(name),m_phone(pname){
}
//姓名
string m_name;
//手机
phone m_phone;
};
void test2(){
person2 p("张三","苹果max15");
cout<<"p的名字为:"<<p.m_name<<"\t手机为:"<<p.m_phone.m_pname<<endl;
}
//静态成员
//静态成员就是在成员变量和成员函数前加上关键词static,称为静态成员
//静态成员变量:
/*所有对象共享同一份数据
在编译阶段分配内存
类内声明,类外初始化*/
//静态成员函数
/*所有对象共享同一个函数
静态成员函数只能访问静态成员变量*/
class person3{
public:
static void func1(){
m_A = 100;//静态成员函数可以访问静态成员变量
// m_a = 200;//不能访问 非静态成员变量 无法区分到底是哪个对象的成员
cout<<"static void func1调用"<<endl;
}
int m_a;
static int m_A;
private:
//类外访问不到私有静态成员函数
static void func2(){
cout<<"static void func2调用"<<endl;
}
static int m_B;
};
int person3::m_A=100;//类内声明,类外初始化
int person3::m_B=100;//私有类外访问不到
void test3(){
person3 p;
cout<<p.m_A<<endl;
//cout<<p.m_B<<endl;//私有类外访问不到
//所有对象共享同一份数据
person3 p1;
p1.m_A = 200;
cout<<p.m_A<<endl;//m_A = 200,说明所有对象共享同一份数据;
}
void test4(){
//静态成员变量 不属于某个对象上,所有对象都共享同一份数据
//因此静态成员变量有两种访问方式
//1、通过对象进行访问
person3 p;
cout<<p.m_A<<endl;
//2、通过类名进行访问
cout<<person3::m_A<<endl;
}
void test5(){
//1、通过对象访问
person3 p;
//p.func();
//2、通过类名访问
//person3::func();
}
//c++对象模型和this指针
//成员变量和成员函数分开存储
//在c++中,类内的成员变量和成员函数分开存储
//只有非静态成员变量才属于类的对象上
//空对象占用内存空间:1
//this指针概念
//每一个非静态成员函数只会诞生一份函数实例,也就是说多个同类型的对象会共用一块代码
//利用this指针区分对象调用成员
//this指向被调用的成员函数所属的对象
//this指针是隐含每一个非静态成员函数内的一种指针
//this指针不需要定义,直接使用即可
//this指针的用途:
//当形参和成员变量同名时,可用this指针来区分
//在类的非静态成员函数中返回对象本身,return *this
class person4{
public:
person4(int age){
//this指向被调用的成员函数所属的对象
this->age = age;
}
person4& addage(person4 &p){
this->age += p.age;
//this指向p1的指针,而*this指向的就是p1这个对象本体
return *this;
}
int age;
};
//解决名称冲突
void test6(){
person4 p(18);
cout<<"p的年龄为:"<<p.age<<endl;
}
//返回对象本身用*this
void test7(){
person4 p(10);
person4 p1(10);
p1.addage(p).addage(p).addage(p);
cout<<"p1 的年龄为:"<<p1.age<<endl;
}
//空指针调用成员函数
class person5{
public:
void showclassname(){
cout<<"this is person class"<<endl;
}
void showpersonage(){
if(this == NULL){
return;
}
//报错原因是因为传入的指针是为NULL
cout<<"age = "<<this->m_age<<endl;
}
int m_age;
};
void test8(){
person5 *p = NULL;
p->showclassname();
p->showpersonage();//运行不了这段程序
}
//const修饰成员函数
//常函数:
//成员函数加入const后我们称这个函数为常函数
//常函数内不可以修改成员属性
//成员属性声明时加关键字mutable后,在常函数中依然可以修改
class person6{
public:
//this指针的本质 是指针常量 指针的指向是不可以修改的
person6(int a,int b):m_a(a),m_b(b)
{
}
void showperson6()const{
//this = NULL;//this指针不可以修改指针的指向的
//this->m_a = 100; //加入const之后this指针指向的值不能修改
this->m_b = 100;
}
int m_a;
mutable int m_b; //特殊变量,即使在常函数中,也可以修改这个值
};
//常对象:
//声明对象前加const称该对象为常对象
//常对象只能调用常函数
void test9(){
//定义常对象时一定要列表初始化
const person6 p(100,200);
//p.m_a =100;
p.m_b = 200;//特殊变量,在常对象中,也可以修改这个值
//常对象只能调用常函数
p.showperson6();
cout<<p.m_a<<p.m_b<<endl;
}
//友元 friend
//友元的目的就是让一个函数或者类访问另一个类中私有成员
//全局函数做友元
class building{
//goodgay全局函数是building好朋友,可以访问building中私有成员
friend void goodgay(building *building);
//Goodgay类是building好朋友,可以访问building中私有成员
friend class Goodgay;
public:
building(){
m_sittingroom="客厅";
m_bedroom = "卧室";
}
public:
string m_sittingroom;
private:
string m_bedroom;
};
void goodgay(building *building){
cout<<"好基友全局函数 正在访问:"<<building->m_sittingroom<<endl;
cout<<"好基友全局函数 正在访问:"<<building->m_bedroom<<endl;
}
test10(){
building bui;
goodgay(&bui);
}
//类做友元
class Goodgay{
public:
Goodgay(){
//创建建筑物对象
bul = new building;
}
building *bul;
void visit(){
cout<<"好基友正在访问"<<bul->m_sittingroom<<endl;
cout<<"好基友正在访问"<<bul->m_bedroom<<endl;
}
};
test11(){
Goodgay p;
p.visit();
}
//成员函数做友元
//building中调用goodgay,而goodgay又调用building,故初始化函数应写在类之后
//定义和类实现分离
//类实现写在两个类定义之后
class building1;
class goodgay1{
public:
goodgay1();
public:
building1 *bul;
void visit1();
void visit2();
};
class building1{
//visit1 成员函数是building1的friend
friend void goodgay1::visit1();
public:
building1();
public:
string m_sitting;
private:
string m_bedroom;
};
building1::building1(){
m_sitting = "客厅";
m_bedroom = "卧室";
}
goodgay1::goodgay1(){
bul = new building1;
}
void goodgay1::visit1(){
cout<<"vist1正在访问"<<bul->m_sitting<<endl;
cout<<"vist1正在访问"<<bul->m_bedroom<<endl;
}
void goodgay1::visit2(){
cout<<"vist2正在访问"<<bul->m_sitting<<endl;
//cout<<"vist2正在访问"<<bul->m_bedroom<<endl;
}
void test12(){
goodgay1 p;
p.visit1();
p.visit2();
}
int main(){
//浅拷贝和深拷贝
test();
//初始化列表
test1();
//类对象作为类成员
test2();
//静态成员变量:
test3();
//test4();
//静态成员函数
test5();
//this指针
test6();
test7();
//空指针调用成员函数
test8();
//常对象和常函数
test9();
//友元
//全局函数做友元
test10();
//类作为友元
test11();
//全员函数做友元
test12();
system("pause");
return 0;
}
案例
立方体类
#include<iostream>
#include<string>
using namespace std;
//设计立方体类(club)
//求出立方体的面积和体积
//分别用全局函数和成员函数判断两个立方体是否相等
class club{
private:
double m_l,m_w,m_h;
public:
void setlwh(double l, double w, double h){
m_l=l;
m_w=w;
m_h=h;
}
double getl(){
return m_l;
}
double geth(){
return m_h;
}
double getw(){
return m_w;
}
double s(){
return 2*(m_l*m_w+m_l*m_h+m_w*m_h);
};
double m(){
return m_l*m_w*m_h;
}
// 利用成员函数判断
bool issamebyclass(club &c){
if(m_l==c.getl()&&m_h==c.geth()&&m_w==c.getw()){
return true;
}
else{
return false;
}
}
};
bool issame(club &c1,club &c2){
if(c1.getl()==c2.getl()&&c1.geth()==c2.geth()&&c1.getw()==c2.getw()){
return true;
}
else{
return false;
}
}
int main(){
club c1;
c1.setlwh(3,4,5);
cout<<"立方体:"<<endl<<"长"<<c1.getl()
<<"\t宽:"<<c1.getw()<<"\t高:"<<c1.geth()
<<"\t面积:"<<c1.s()<<"\t体积"<<c1.m()<<endl;
club c2;
c2.setlwh(3,4,5);
if(issame(c1,c2)){
cout<<"全局函数判断c1和c2相等"<<endl;
}
else{
cout<<"全局函数判断c1和c2不相等"<<endl;
}
if(c1.issamebyclass(c2)){
cout<<"成员函数判断c1和c2相等"<<endl;
}
else{
cout<<"成员函数判断c1和c2不相等"<<endl;
}
}
点和圆关系
#include<iostream>
#include<string>
using namespace std;
//设计一个圆形circle类,和一个点point类。计算点和圆的关系
class circle{
private:
double m_x,m_y,m_r;
public:
void setxyr(double x,double y, double r){
m_x = x;
m_y = y;
m_r = r;
}
double getx(){
return m_x;
}
double gety(){
return m_y;
}
double getr(){
return m_r;
}
};
class point{
private:
double m_x,m_y;
public:
void setxy(double x,double y){
m_x = x;
m_y = y;
}
int getx(){
return m_x;
}
int gety(){
return m_y;
}
// 点和圆的关系
void cpc(circle &c){
double p_distance=(c.getx()-m_x)*(c.getx()-m_x)+(c.gety()-m_y)*(c.gety()-m_y);
double r_distance=c.getr()*c.getr();
if(p_distance==r_distance){
cout<<"该点在圆上"<<endl;
}
else if(p_distance>r_distance){
cout<<"该点在圆外"<<endl;
}
else{
cout<<"该点在圆内"<<endl;
}
}
};
int main(){
circle c;
c.setxyr(3,4,5);
point p1,p2,p3;
//圆内的点
p1.setxy(3,4);
//圆上的点
p2.setxy(0,0);
//圆外的点
p3.setxy(10,17);
p1.cpc(c);
p2.cpc(c);
p3.cpc(c);
system("pause");
return 0;
}
点和圆关系分文件实现
main.cpp
#include<iostream>
#include"point.h"
#include"circle.h"
int main(){
circle c;
c.setxyr(3,4,5);
point p1,p2,p3;
//圆内的点
p1.setxy(3,4);
//圆上的点
p2.setxy(0,0);
//圆外的点
p3.setxy(10,17);
p1.cpc(c);
p2.cpc(c);
p3.cpc(c);
system("pause");
return 0;
}
circle.cpp
#include<iostream>
#include"point.h"
#include"circle.h"
int main(){
circle c;
c.setxyr(3,4,5);
point p1,p2,p3;
//圆内的点
p1.setxy(3,4);
//圆上的点
p2.setxy(0,0);
//圆外的点
p3.setxy(10,17);
p1.cpc(c);
p2.cpc(c);
p3.cpc(c);
system("pause");
return 0;
}
circle.h
#pragma once
#include<iostream>
using namespace std;
class circle{
private:
double m_x,m_y,m_r;
public:
void setxyr(double x,double y, double r);
double getx();
double gety();
double getr();
};
point.cpp
#include"point.h"
void point::setxy(double x,double y){
m_x = x;
m_y = y;
}
int point::getx(){
return m_x;
}
int point::gety(){
return m_y;
}
// 点和圆的关系
void point::cpc(circle &c){
double p_distance=(c.getx()-m_x)*(c.getx()-m_x)+(c.gety()-m_y)*(c.gety()-m_y);
double r_distance=c.getr()*c.getr();
if(p_distance==r_distance){
cout<<"该点在圆上"<<endl;
}
else if(p_distance>r_distance){
cout<<"该点在圆外"<<endl;
}
else{
cout<<"该点在圆内"<<endl;
}
}
point.h
#pragma once
#include<iostream>
#include"circle.h"
using namespace std;
class point{
private:
double m_x,m_y;
public:
void setxy(double x,double y);
int getx();
int gety();
// 点和圆的关系
void cpc(circle &c);
};