#include
using namespace std;
//C++用类求阶乘
class fact
{
private:
int n;//n是要求的阶乘 控制循环次数
int ret;//ret存放结果
public:
void assign(int x,int y)
{
n=x;
ret=y;
}
int fac()
{
int i;
for(i=1;i<=n;i++)
{
ret*=i;
}
return ret;
}
};
int main()
{
fact f;
f.assign(3,1);
//int k=f.fac();
//cout<
cout<<f.fac()<<endl;
return 0;
}
#include
using namespace std;
//设计一个圆类,求圆的周长
//圆求周长的公式:2*pi*半径
class fact
{
private:
int n;//n是要求的阶乘 控制循环次数
int ret;//ret存放结果
public:
void assign(int x,int y);
int fac();
};
void fact::assign(int x,int y)
{
n=x;
ret=y;
}
int fact::fac()
{
int i;
for(i=1;i<=n;i++)
{
ret*=i;
}
return ret;
}
int main()
{
fact f;
f.assign(3,1);
//int k=f.fac();
//cout<
cout<<f.fac()<<endl;
return 0;
}
#include
using namespace std;
#define PI 3.14
//设计一个圆类,求圆的周长
//圆求周长的公式:2*pi*半径
class Circle//类名
{
//访问权限
private:
int m_r;//成员变量 半径
public:
//行为 给圆的半径赋值
void assign(int r);
//获取圆的半径
int get();
//获取圆的周长
double calculateZC();
};
void Circle::assign(int r)
{
m_r=r;
}
int Circle::get()
{
return m_r;
}
double Circle::calculateZC()
{
return 2*PI*m_r;
}
int main()
{
//通过圆类 创建具体的圆的对象
Circle c;
//调用成员函数assign给圆的半径赋值
c.assign(10);
//调用成员函数get获取圆的半径
cout<<"圆的半径是"<<c.get()<<endl;
//调用成员函数calculateZC获取圆的周长
cout<<"圆的周长是"<<c.calculateZC()<<endl;
return 0;
}
//设计一个学生类,属性有姓名和学号,可以给姓名和学号赋值,可以显示学生的姓名和学号
#include
#include
using namespace std;
class Student//类名
{
//访问权限
private:
string m_name;//成员变量
int m_id;
public:
//行为 给姓名和学号赋值
void assign(string name,int id);
//显示学生的姓名和学号
void show();
};
void Student::assign(string name,int id)
{
m_name=name;
m_id=id;
}
void Student::show()
{
cout<<"学生的姓名是"<<m_name<<"学号是"<<m_id<<endl;
}
int main()
{
//通过学生类 创建具体的学生的对象
Student s;
//调用成员函数assign给学生的姓名和学号赋值
s.assign("aa",10);
//调用成员函数show显示学生的姓名和学号
s.show();
return 0;
}
//设计一个学生类,属性有姓名和学号,可以给姓名和学号赋值,可以显示学生的姓名和学号
#include
#include
using namespace std;
class Student//类名
{
//访问权限
private:
string m_name;//成员变量
int m_id;
public:
//行为 给姓名和学号赋值
void assign(string name,int id);
//显示学生的姓名和学号
void show();
};
void Student::assign(string name,int id)
{
m_name=name;
m_id=id;
}
void Student::show()
{
cout<<"学生的姓名是"<<m_name<<"学号是"<<m_id<<endl;
}
int main()
{
//通过学生类 创建具体的学生的对象
Student s;
string s1;
int i;
cin>>s1>>i;
//调用成员函数assign给学生的姓名和学号赋值
s.assign(s1,i);
//调用成员函数show显示学生的姓名和学号
s.show();
return 0;
}
#include
#include
using namespace std;
class Person
{
public:
//公共权限
string m_name;
protected:
//保护权限
string m_car;
private:
//私有权限
int m_password;
public:
//在类内不管何种访问权限都是可以直接访问的
void fun()
{
m_name="小王";
m_car="benchi";
m_password=123;
}
};
int main()
{
//实例化具体对象
Person p;
p.m_name="小李";
//p.m_car="奔驰";//保护权限内容 在类外访问不到
//p.m_password=123456;//私有权限内容 在类外访问不到
return 0;
}
struct默认权限是公共 public
class默认权限是公共 private
优点1:将所有成员属性设置为私有,可以自己控制读写权限
优点2:对于写权限,我们可以检测数据的有效性
#include
#include
using namespace std;
class Person
{
private:
//姓名 可读可写
string m_name;
//年龄 只读
int m_age;
//学号 只写
int m_id;
public:
//写姓名
void setName(string name)
{
m_name=name;
}
//读姓名
string getName()
{
return m_name;
}
//写年龄
void setAge(int age)
{
if(age<0||age>150)
{
m_age=0;
cout<<"年龄有误"<<endl;
return ;
}
m_age=age;
}
//读年龄
int getAge()
{
return m_age;
}
//写学号
void setId(int id)
{
m_id=id;
}
};
int main()
{
//实例化具体对象
Person p;
p.setName("小李");
cout<<"姓名:"<<p.getName()<<endl;
p.setAge(18);
cout<<"年龄:"<<p.getAge()<<endl;
//设置id 但不能得到id
p.setId(20);
return 0;
}
1.创建立方体类
2.设计属性
3.设计行为 获取立方体面积和体积
4.分别利用全局函数和成员函数是否相等
#include
using namespace std;
class Cube
{
private:
double m_L;
double m_H;
double m_W;
public:
void Set(double l, double h, double w)
{
m_L = l;
m_H = h;
m_W = w;
}
double getL()
{
return m_L;
}
double getH()
{
return m_H;
}
double getW()
{
return m_W;
}
double Volume()
{
return m_L * m_H * m_W;
}
double Area()
{
return 2 * m_L * m_H + 2 * m_L * m_W + 2 * m_W * m_H;
}
//成员函数判断是否相等
bool isSameByClass(Cube& c)
{
if (m_L == c.getL() && m_H == c.getH() && m_W == c.getW())
{
return 1;
}
else
return 0;
}
};
//全局函数判断是否相等
bool isSame(Cube& c1, Cube& c2)
{
if (c1.getL() == c2.getL() && c1.getH() == c2.getH() && c1.getW() == c2.getW())
{
return 1;
}
else
return 0;
}
int main()
{
Cube c1;
c1.Set(10, 10, 10);
cout << "c1的面积" << c1.Area() << endl;
cout << "c1的体积" << c1.Volume() << endl;
Cube c2;
c2.Set(10, 10, 11);
bool ret = isSame(c1, c2);
if (ret)
{
cout << "全局函数判断相等" << endl;
}
else
cout << "全局函数判断不相等" << endl;
bool ret2 = c1.isSameByClass(c2);
if (ret2)
{
cout << "成员函数判断相等" << endl;
}
else
cout << "成员函数判断不相等" << endl;
return 0;
}
#include
using namespace std;
//练习案例
//设计一个圆形类,和一个点类,计算点和圆的关系
class Point
{
private:
int m_X;
int m_Y;
public:
void setX(int x)
{
m_X = x;
}
void setY( int y)
{
m_Y = y;
}
int getX()
{
return m_X;
}
int getY()
{
return m_Y;
}
};
class Circle
{
private:
int m_R;
Point m_Center;
public:
void setR(int r)
{
m_R = r;
}
int getR()
{
return m_R;
}
void setCenter(Point Center)
{
m_Center = Center;
}
Point getCenter()
{
return m_Center;
}
};
//判断点和圆的关系
void isInCircle(Circle& c, Point& p)
{
int distance = (c.getCenter().getX() - p.getX()) * (c.getCenter().getX() - p.getX()) +
(c.getCenter().getY() - p.getY()) * (c.getCenter().getY() - p.getY());
int rDistance = c.getR() * c.getR();
if (distance == rDistance)
{
cout << "点在圆上" << endl;
}
else if (distance > rDistance)
{
cout << "点在圆外" << endl;
}
else
{
cout << "点在圆内" << endl;
}
}
int main()
{
//创建圆
Circle c;
c.setR(10);
Point center;
center.setX(10);
center.setY(0);
c.setCenter(center);
//创建点
Point p;
p.setX(10);
p.setY(9);
isInCircle(c, p);
return 0;
}
构造函数主要作用于创建对象时为对象的成员属性赋值,构造函数由编译器自动调用,无需手动调用。
析构函数主要作用于在对象销毁前系统自动调用,执行一些清理工作。
#include
using namespace std;
class Person
{
public:
Person();//构造函数
~Person();//析构函数
private:
};
Person::Person()
{
cout << "Person的构造函数调用" << endl;
}
Person::~Person()
{
cout << "Person的析构函数调用" << endl;
}
int main()
{
Person p;
return 0;
}
两种分类方式:
按参数分类:有参构造和无参构造(默认构造)
按类型分类:普通构造和拷贝构造
三种调用方式
括号法
显示法
隐式转换法
#include
using namespace std;
class Person
{
public:
Person();//无参构造函数
Person(int a);//有参构造函数
Person(const Person &p);//拷贝构造函数
~Person();//析构函数
int age;
};
Person::Person()
{
cout << "Person的无参构造函数调用" << endl;
}
Person::Person(int a)
{
age=a;
cout << "Person的有参构造函数调用" << endl;
}
//拷贝构造函数
Person::Person(const Person &p)
{
age=p.age;
cout << "Person的拷贝构造函数调用" << endl;
}
Person::~Person()
{
cout << "Person的析构函数调用" << endl;
}
int main()
{
//调用构造函数的方法
//括号法
Person p1;//无参构造函数调用
Person p2(10);//有参构造函数调用
Person p3(p2);//拷贝构造函数调用
cout<<"p2的年龄为"<<p2.age<<endl;
cout<<"p3的年龄为"<<p3.age<<endl;
//显示法
Person p1;//无参构造函数调用
Person p2 = Person(10);//有参构造函数调用
Person p3 = Person(p2);//拷贝构造函数调用
//隐式转换法
Person p4=10;//==Person p4= Person(10);
Person p5=P4;//拷贝构造函数
return 0;
}
三种情况:
使用一个已经1创建完毕的对象来初始化一个新对象
值传递的方式给函数参数赋值
值方式返回局部对象
#include
using namespace std;
class Person
{
public:
Person();//构造函数
~Person();//析构函数
Person(int age);//有参构造函数
Person(const Person &p);//拷贝构造函数
private:
int m_age;
};
Person::Person()
{
cout << "Person的构造函数调用" << endl;
}
Person::Person(int age)
{
cout << "Person的有参构造函数调用" << endl;
m_age=age;
}
Person::Person(const Person &p)
{
cout << "Person的拷贝构造函数调用" << endl;
m_age=p.m_age;
}
Person::~Person()
{
cout << "Person的析构函数调用" << endl;
}
void dowork(Person p)
{
}
Person dowork2()
{
Person p1;
return p1;
}
int main()
{
Person p;
Person p1(10);
Person p2(p1);
//值传递的方式给函数参数赋值
Person p3;
dowork(p3);
//值方式返回局部对象
Person p4=dowork2();
return 0;
}
默认规则下,C++编译器至少给一个类添加三个函数
1.默认构造函数(无参,函数体为空)
2.默认析构函数(无参,函数体为空)
3.默认拷贝构造函数,对属性进行值拷贝
构造函数调用规则如下:
如果用户定义有参构造函数,c++不再提供默认无参构造,但是会提供默认拷贝构造
如果用户定义拷贝构造函数,c++不会在提供其他构造函数
浅拷贝:编译器提供的默认拷贝构造函数
深拷贝:在堆区重新申请空间,进行拷贝工作
#include
using namespace std;
class Person
{
public:
Person();//构造函数
~Person();//析构函数
Person(int age,int height);//有参构造函数
Person(const Person &p);//拷贝构造函数
int m_age;
int* m_height;
};
Person::Person(int age,int height)
{
cout << "Person的有参构造函数调用" << endl;
m_age=age;
m_height=new int(height);
}
//自己实现拷贝构造函数,解决浅拷贝带来的问题
Person::Person(const Person &p)
{
cout << "Person的拷贝构造函数调用" << endl;
m_age=p.m_age;
//height=p.m_height这是编译器实现的默认拷贝构造函数
//深拷贝操作
m_height=new int(*p.m_height);
}
Person::~Person()
{
//析构代码,将堆区开辟数据做释放操作
if(m_height!=NULL)
{
delete m_height;
}
cout << "Person的析构函数调用" << endl;
}
int main()
{
Person p1(10,160);
cout<<"p1 "<<p1.m_age<<" "<<*p1.m_height<<endl;
Person p2(p1);
//浅拷贝都带来的问题就是对取得内存重复释放
//浅拷贝的问题要利用深拷贝来解决
//如果利用编译器提供的拷贝构造函数,会做浅拷贝操作
cout<<"p2 "<<p2.m_age<<" "<<*p2.m_height<<endl;
return 0;
}
初始化列表用于给类中的私有成员变量初始化
语法:构造函数():属性1(值1),属性2(值2)…{}
#include
#include
using namespace std;
class Person
{
public:
//传统初始化工作
//Person(int age,int height,string name);//有参构造函数
//初始化列表初始化属性
Person(int age,int height,string name);
~Person();//析构函数
int m_age;
int m_height;
string m_name;
};
//1.赋值形式
/*Person::Person(int age,int height,string name)
{
m_age=age;
m_height=height;
m_name=name;
}*/
//2.初始化列表初始化属性
Person::Person(int age,int height,string name):m_age(age),m_height(height), m_name(name)
{
}
Person::~Person()
{
}
int main()
{
Person p1(10,160,"wk");
cout<<p1.m_age<<" "<<p1.m_height<<" "<<p1.m_name<<endl;
return 0;
}
C++类中的成员可以是另一个类的成员,我们称该成员为对象成员
class A {};
class B
{
A a;
};
B类中有对象A作为成员,A为对象成员
#include
#include
using namespace std;
class Phone
{
public:
Phone(string pName)
{
m_pName=pName;
cout<<"Phone构造函数"<<endl;
}
string m_pName;
};
class Person
{
public:
Person(string name,string phone):m_name(name),m_phone(phone)
{
cout<<"Person构造函数"<<endl;
}
string m_name;
Phone m_phone;
};
//当其他类对象最为本类成员,构造时先构造类对象
//在构造自身。析构与构造相反
int main()
{
//Phone p1();
Person p("wk","苹果");
cout<<p.m_name<<"拿着 "<<p.m_phone.m_pName<<endl;
return 0;
}
静态成员就是在成员变量和成员函数前加上关键字static,称为静态成员。
静态成员分为:
静态成员变量
所有对象共享同一份数据
在编译阶段分配内存
类内声明,类外初始化
静态成员函数
所有对象共享同一个函数
静态成员函数只能访问静态成员变量
#include
using namespace std;
class Person
{
public:
//1.所有对象都共享同一份数据
//2.编译阶段就分配内存
//3.类内声明,类外初始化操作
static int m_a;
//静态成员变量也是有访问权限的
private:
static int m_b;
};
int Person::m_a=100;
int Person::m_b=200;
int main()
{
Person p;
cout<<p.m_a<<endl;
Person p2;
p2.m_a=200;
cout<<p.m_a<<endl;
//静态成员变量 不属于某个对象上,所有对象共享同一份数据
//因此静态成员变量有两种访问方式
//1.通过对象进行访问
Person p3;
cout<<p3.m_a<<endl;
//2.通过类名进行访问
cout<<Person::m_a<<endl;
//cout<
return 0;
}
#include
using namespace std;
class Person
{
public:
//1.所有对象都共享同一个函数
//2.静态成员函数只能访问静态成员变量
static void func()
{
cout<<"static void func调用"<<endl;
}
static int m_a;//静态成员变量
private:
static void func2()
{
cout<<"static void func2调用"<<endl;
}
};
int main()
{
//1.通过对象进行访问
Person p;
p.func();
//2.通过类名进行访问
Person::func();
//Person::func2();私有权限访问不到
return 0;
}
在C++中,类内的成员变量和成员函数分开存储
只有非静态成员变量才属于类的对象上
成员变量和成员函数分开存储
#include
using namespace std;
class Person
{
public:
int m_a;//非静态的成员变量 属于类的对象上
static int m_b;//非静态成员变量 不属于类对象上
void func(){}//非静态成员函数 不属于类的对象上
static void func2(){}//静态成员函数 不属于类的对象上
};
int Person::m_b=0;
int main()
{
Person p;
//空对象占用内存空间为1个字节
cout<<"sizeof p="<<sizeof(p)<<endl;
return 0;
}
构造函数的目的是给类的私有成员变量赋值
涉及到this指针 this相当于是一个隐式的指针
指向这个类的成员变量 此时成员函数的形参可以和类的私有成员变量的名称相同
每一个非静态成员函数只会诞生一份函数实例,也就是说多个同类型的对象会共用一块代码
这一块代码是如何区分哪个对象调用自己的呢?
c++提供特殊的对象指针:this指针,this指针指向被调用的成员函数所属的对象。
this指针的用于:1.解决名称冲突2.返回对象本身用*this
#include
using namespace std;
class Person
{
public:
int age;
//1.解决名称冲突
Person(int age)
{
//this指针指向被调用的成员函数所属的对象
this->age=age;
}
Person& PersonAddAge(Person &p)
{
this->age+=p.age;
return *this;
}
};
//2.返回对象本身用*this
int main()
{
Person p1(18);
Person p2(18);
cout<<p1.age<<endl;
p2.PersonAddAge(p1).PersonAddAge(p1).PersonAddAge(p1);
cout<<p2.age<<endl;
return 0;
}
运算符重载概念:对已有的运算符重新进行定义,赋予其另一种功能,以适应不同的数据类型。
括号法
转换法
通过成员函数重载+号
#include
using namespace std;
class Person
{
public:
int m_a;
int m_b;
Person()
{}
Person(int a,int b)
{
this->m_a=a;
this->m_b=b;
}
Person operator+(Person& p)
{
Person temp;
temp.m_a=this->m_a+p.m_a;
temp.m_b=this->m_b+p.m_b;
return temp;
}
};
int main()
{
Person p1(10,20);
Person p2(10,20);
//正常调用情况
Person p3=p1.operator +(p2);
//简化形式
//Person p3=p1+(p2);
cout<<p3.m_a<<" "<<p3.m_b<<endl;
return 0;
}
通过全局函数重载+号
#include
using namespace std;
class Person
{
public:
int m_a;
int m_b;
Person()
{}
Person(int a,int b)
{
this->m_a=a;
this->m_b=b;
}
};
Person operator+(Person& p1,Person& p2)
{
Person temp;
temp.m_a=p1.m_a+p2.m_a;
temp.m_b=p1.m_b+p2.m_b;
return temp;
}
int main()
{
Person p1(10,20);
Person p2(10,20);
//正常调用情况
//Person p3=operator+(p1,p2);
//简化形式
Person p3=p1+(p2);
cout<<p3.m_a<<" "<<p3.m_b<<endl;
return 0;
}
运算符重载,也可以发生函数重载
#include
using namespace std;
class Person
{
public:
int m_a;
int m_b;
Person()
{}
Person(int a,int b)
{
this->m_a=a;
this->m_b=b;
}
};
Person operator+(Person& p1,int num)
{
Person temp;
temp.m_a=p1.m_a+num;
temp.m_b=p1.m_b+num;
return temp;
}
int main()
{
Person p1(10,20);
Person p2(10,20);
//正常调用情况
//Person p3=operator+(p1,100);
//简化形式
Person p3=p1+100;//Person+int
cout<<p3.m_a<<" "<<p3.m_b<<endl;
return 0;
}
#include
using namespace std;
class Person
{
public:
int m_a;
int m_b;
Person()
{}
Person(int a,int b)
{
this->m_a=a;
this->m_b=b;
}
Person operator+(int num)
{
Person temp;
temp.m_a=m_a+num;
temp.m_b=m_b+num;
return temp;
}
};
int main()
{
Person p1(10,20);
Person p2(10,20);
//正常调用情况
//Person p3=p1.operator+(100);
//简化形式
Person p3=p1+100;//Person+int
cout<<p3.m_a<<" "<<p3.m_b<<endl;
return 0;
}
#include
using namespace std;
class Person
{
public:
/*Person operator+(Person &p);*/
int m_a;
int m_b;
private:
};
//全局函数重载+号
//Person operator+(Person& p1, Person& p2)
//{
// Person temp;
// temp.m_a = p1.m_a + p2.m_a;
// temp.m_b = p1.m_b + p2.m_b;
// return temp;
//}
Person operator+(Person& p1, int num)
{
Person temp;
temp.m_a = p1.m_a + num;
temp.m_b = p1.m_b + num;
return temp;
}
//通过成员函数重载
//Person Person::operator+(Person& p)
//{
// Person temp;
// temp.m_a = this->m_a + p.m_a;
// temp.m_b = this->m_b + p.m_b;
// return temp;
//}
int main()
{
Person p1;
p1.m_a = 10;
p1.m_b = 20;
Person p2;
p2.m_a = 10;
p2.m_b = 20;
//Person p3 = p1 + p2;//Person p3=p1.operator+(p2)
//cout << p3.m_a << endl;
//cout << p3.m_b << endl;
//通过成员函数重载+号本质
//Person p3=p1.operator+(p2)==Person p3 = p1 + p2;
//通过成员函数重载+号本质
//Person p3=p1.operator+(p2)
//Person p3=operator+(p1,p2)==Person p3 = p1 + p2;
//运算符重载 也可以发生函数重载
Person p3 = p1 + 10;
cout << p3.m_a << endl;
cout << p3.m_b << endl;
return 0;
}
可以输出自定义数据类型
#include
using namespace std;
class Person
{
public:
friend ostream& operator<<(ostream& cout, Person& p);
Person()
{}
Person(int a, int b)
{
this->m_a = a;
this->m_b = b;
}
private:
int m_a;
int m_b;
//不能利用成员函数重载<<运算符,因为无法实现 cout在左侧
};
//全局函数重载<<运算符
ostream& operator<<(ostream& cout, Person& p)
{
cout << p.m_a << " " << p.m_b;
return cout;
}
int main()
{
Person p1(10, 20);
Person p2(10, 20);
//标准调用
operator<<(cout, p1) << endl;
//简化版本
//cout<
return 0;
}
前置递增运算符重载
#include
using namespace std;
class MyInteger
{
friend ostream& operator<<(ostream& cout, MyInteger& myint);
public:
MyInteger()
{
m_num = 0;
}
//重载前置++运算符
//MyInteger& operator++()
//{
// //先进行++运算
// m_num++;
// //再返回自身
// return *this;
//}
//重载后置++运算符
MyInteger operator++(int)//int 代表占位参数,可以用于区分前置和后置递增
{
//先记录当时的结果
MyInteger temp = *this;
//后递增
m_num++;
return temp;
}
private:
int m_num;
};
//重载左移运算符
ostream& operator<<(ostream & cout, MyInteger& myint)
{
cout << myint.m_num;
return cout;
}
int main()
{
MyInteger myint;
//cout << myint++ << endl;
cout << myint << endl;
//cout << ++(++myint) << endl;
return 0;
}
C++编译器至少给一个类添加四个函数
1、默认构造函数(无参,函数体为空)
2、默认析构函数(无参,函数体为空)
3、默认拷贝构造函数,对属性值进行拷贝
4、赋值运算符operator=对属性进行值拷贝
#include
using namespace std;
class Person
{
public:
Person(int age)
{
m_age = new int(age);
}
~Person()
{
}
Person& operator+(Person &p)
{
if (m_age != NULL)
{
delete m_age;
}
m_age = new int(*p.m_age);
return *this;
}
int* m_age;
private:
};
int main()
{
Person p1(18);
Person p2(20);
Person p3(30);
p3 = p2 = p1;
cout << *p1.m_age << endl;
cout << *p2.m_age << endl;
cout << *p3.m_age << endl;
return 0;
}
#include
using namespace std;
class Person
{
public:
Person(string name,int age)
{
m_name = name;
m_age = age;
}
bool operator==(Person &p)
{
if (this->m_name==p.m_name&&this->m_age==p.m_age)
{
return true;
}
return false;
}
bool operator!=(Person &p)
{
if (this->m_name==p.m_name&&this->m_age==p.m_age)
{
return false;
}
return true;
}
string m_name;
int m_age;
private:
};
int main()
{
Person p1("hi",18);
Person p2("hi",18);
if( p1 ==p2)
{
cout<<"相等"<<endl;
}
return 0;
}
由于重载后使用的方式非常像函数的调用,因此被称为仿函数
#include
#include
using namespace std;
class Person
{
public:
//重载()运算符
void operator()(string test)
{
cout<<test<<endl;
}
private:
};
void myprint(string test)
{
cout<<test<<endl;
}
int main()
{
Person p1;
// p1.operator ()("hello");
p1("hello");
myprint("hello");
return 0;
}
继承的语法:class 子类:继承方式 父类
#include
using namespace std;
class Base1
{
public:
int m_a;
protected:
int m_b;
private:
int m_c;
};
//公共继承
class Son1:public Base1
{
public:
void func()
{
m_a=10;//父类中的公共权限成员 到子类中依然是公共权限
m_b=10;//父类中的保护权限成员 到子类中依然是保护权限
//m_c=10;//父类中的私有权限成员 子类访问不到
}
};
//保护继承
class Son2:protected Base1
{
public:
void func()
{
m_a=10;//父类中的公共权限成员 到子类中变为保护权限
m_b=10;//父类中的保护权限成员 到子类中是保护权限
//m_c=10;//父类中的私有权限成员 子类访问不到
}
};
//私有继承
class Son3:private Base1
{
public:
void func()
{
m_a=10;//父类中的公共权限成员 到子类中变为私有权限
m_b=10;//父类中的保护权限成员 到子类中是私有权限
//m_c=10;//父类中的私有权限成员 子类访问不到
}
};
class GrandSon3:public Son3
{
public:
void func()
{
//m_a=1000;//访问不到 ,因为Son3中的成员变量是私有继承来的,类外都访问不到
}
};
int main()
{
//public权限在类内类外都可以访问
//protected权限在子类中可以访问 但在类外不可访问
//private权限只能在本类中使用
Son1 s1;
s1.m_a=100;
//s1.m_b=100;//在son1中 m_b是保护权限,类外不可访问
Son2 s2;
//s2.m_a=1000;//到son2中 m_a变为保护权限,类外不可访问
//s2.m_b=1000;//在son2中 m_b保护权限,类外不可访问
Son3 s3;
//s3.m_a=1000;//到Son3中变为私有成员 类外访问不到
//s3.m_b=1000;//到Son3中变为私有成员 类外访问不到
}
子类继承父类后,当创建子类对象,也会调用父类的构造函数。
#include
using namespace std;
class Base1
{
public:
Base1()
{
cout<<"Base1构造函数"<<endl;
}
~Base1()
{
cout<<"Base1析构函数"<<endl;
}
};
//公共继承
class Son1:public Base1
{
public:
Son1()
{
cout<<"Son1构造函数"<<endl;
}
~Son1()
{
cout<<"Son1析构函数"<<endl;
}
};
int main()
{
//Base1 b;
Son1 s;//先构造父类的,在构造子类,析构与构造顺序相反
return 0;
}
当子类与父类出现同名的成员,如何通过子类对象,访问到子类或父类中同名的数据?
访问子类同名成员 直接访问即可
访问父类同名成员 需要加作用域
#include
using namespace std;
//继承中同名成员处理
class Base1
{
public:
Base1()
{
m_a=100;
}
int m_a;
void func()
{
cout<<"Base1"<<endl;
}
};
//公共继承
class Son1:public Base1
{
public:
Son1()
{
m_a=200;
}
int m_a;
void func()
{
cout<<"Son1"<<endl;
}
};
int main()
{
Son1 s;
cout<<s.m_a<<endl;//如果同名访问的是子类
cout<<s.Base1::m_a<<endl;//如果需要访问父类,则需要加上作用域
s.func();//直接调用 也是调用子类的同名函数
s.Base1::func();
return 0;
}
C++允许一个类继承多个类
语法:class 子类: 继承方式 父类 1,继承方式 父类2 …
多继承可能会引发父类中有同名成员出现,需要加作用域区分
#include
using namespace std;
//继承中同名成员处理
class Base1
{
public:
Base1()
{
m_a=100;
}
int m_a;
};
class Base2
{
public:
Base2()
{
m_a=200;
}
int m_a;
};
//子类 需要继承 Base1和Base2
class Son1:public Base1,public Base2
{
public:
Son1()
{
m_c=300;
m_d=400;
}
int m_c;
int m_d;
};
int main()
{
Son1 s;
cout<<"sizeof Son="<<sizeof(s)<<endl;
//当父类中出现同名成员,需要加作用域区分
cout<<"Base1::m_a "<<s.Base1::m_a<<endl;
cout<<"Base2::m_a "<<s.Base2::m_a<<endl;
return 0;
}
菱形继承概念:
两个派生类继承同一个基类
又有某个类同时继承两个派生类
这种继承被称为菱形继承
利用虚继承解决菱形继承的问题
#include
using namespace std;
//继承中同名成员处 理
//继承之前加上关键字virtual 变为虚继承
//Animal成为虚基类
class Animal
{
public:
int m_Age;
};
class Sheep: virtual public Animal
{
public:
};
class Tuo: virtual public Animal
{
public:
};
//子类 需要继承 Base1和Base2
class SheepTuo:public Sheep,public Tuo
{
public:
};
int main()
{
SheepTuo st;
st.Sheep::m_Age=10;
st.Tuo::m_Age=20;//这个数据只有一个了
cout<<"st.Sheep::m_Age "<<st.Sheep::m_Age<<endl;
cout<<"st.Tuo::m_Age "<<st.Tuo::m_Age<<endl;
return 0;
}
多态是C++面向对象三大特性之一
多态分为两类
静态多态 :函数重载和运算符重载属于静态多态,复用函数名
动态多态:派生类和虚函数实现多态
#include
using namespace std;
class Animal
{
public:
//虚函数
virtual void speak()
{
cout<<"动物再说话"<<endl;
}
};
class Cat: public Animal
{
public:
void speak()
{
cout<<"小猫再说话"<<endl;
}
};
class Dog: public Animal
{
public:
void speak()
{
cout<<"小狗再说话"<<endl;
}
};
//动态多态满足条件
//1.有继承关系
//2.子类重写父类的虚函数
void doSpeak(Animal &animal)
{
animal.speak();
}
int main()
{
Cat cat;
doSpeak(cat);
Dog dog;
doSpeak(dog);
return 0;
}
在多态中,通常父类中虚函数的实现是毫无意义的,主要都是调用子类重写的内容
因此可以将虚函数改为纯虚函数
纯虚函数语法:virtual 返回值类型 函数名 (参数列表)=0;
当类中有了纯虚函数,这个类也称为抽象类
抽象类特点 :
无法实例化对象子类必须重写抽象类中的纯虚函数,否则也属于抽象类
#include
using namespace std;
class Base
{
public:
//纯虚函数
//只要有一个纯虚函数,这个类称为抽象类
//抽象类的特点:
//1.无法实例化对象
//2.抽象类的子类 必须重写父类中的纯虚函数,否则也属于抽象类
virtual void func()=0;
};
class Son:public Base
{
public:
virtual void func()
{
cout<<"func函数调用"<<endl;
}
};
int main()
{
Base* base=new Son;
base->func();
return 0;
}
#include
using namespace std;
class AbstractDrinking
{
public:
//煮水
virtual void Boil()=0;
//冲泡
virtual void Brew()=0;
//倒入杯中
virtual void PourInCup()=0;
//加入辅料
virtual void PutSomething()=0;
void makeDrink()
{
Boil();
Brew();
PourInCup();
PutSomething();
}
};
//制作咖啡
class Coffee:public AbstractDrinking
{
public:
virtual void Boil()
{
cout<<"煮水"<<endl;
}
virtual void Brew()
{
cout<<"冲泡咖啡"<<endl;
}
virtual void PourInCup()
{
cout<<"倒入杯中"<<endl;
}
virtual void PutSomething()
{
cout<<"加入糖和牛奶"<<endl;
}
};
//制作咖啡
class Tea:public AbstractDrinking
{
public:
virtual void Boil()
{
cout<<"煮矿泉水"<<endl;
}
virtual void Brew()
{
cout<<"冲泡茶叶"<<endl;
}
virtual void PourInCup()
{
cout<<"倒入杯中"<<endl;
}
virtual void PutSomething()
{
cout<<"加入柠檬"<<endl;
}
};
//一个接口多个实现
void doWork(AbstractDrinking *abs)//AbstractDrinking *abs=new Coffee
{
abs->makeDrink();
delete abs;
}
int main()
{
doWork(new Coffee);
doWork(new Tea);
return 0;
}
多态使用时,如果子类中有属性开辟到堆区,那么父类指针在释放时无法调佣到子类的析构代码
解决方式 :将父类中的析构函数改为虚析构和纯虚析构
虚析构和纯虚析构共性:
可以解决父类指针释放子类对象
都需要有具体的函数实现
虚析构和纯虚析构区别:
如果是纯虚析构,该类属于抽象类,无法实例化对象
虚析构语法:virtual ~类名(){}
纯虚析构语法:`virtual ~类名()=0;
类名::~类名(){}
#include
#include
using namespace std;
class Animal
{
public:
Animal()
{
cout<<"Animal的构造函数"<<endl;
}
//虚函数
virtual void speak()=0;
//利用虚析构可以解决父类指针释放子类对象时不干净的问题
//virtual ~Animal()//给父类析构加上虚析构,就能够执行子类的析构
//{
//cout<<"Animal的析构函数"<
//}
//纯虚析构
virtual ~Animal()=0;
};
Animal::~Animal()
{
cout<<"Animal的纯虚析构函数"<<endl;
}
class Cat: public Animal
{
public:
Cat(string name)
{
cout<<"Cat的构造函数"<<endl;
m_name=new string(name);
}
virtual void speak()
{
cout<<*m_name<<"小猫再说话"<<endl;
}
string* m_name;
~Cat()
{
if(m_name!=NULL)
{
cout<<"Cat的析构函数"<<endl;
delete m_name;
m_name=NULL;
}
}
};
int main()
{
Animal* animal=new Cat("Tom");
animal->speak();
delete animal;
return 0;
}
#include
#include
using namespace std;
class CPU
{
public:
virtual void calculate()=0;
};
class VideoCard
{
public:
virtual void display()=0;
};
class Memory
{
public:
virtual void storage()=0;
};
class Computer
{
public:
Computer(CPU* cpu,VideoCard* vc,Memory* mem)
{
m_cpu=cpu;
m_vc=vc;
m_mem=mem;
}
void work()
{
m_cpu-> calculate();
m_vc ->display();
m_mem->storage();
}
~Computer()
{
if(m_cpu!=NULL)
{
delete m_cpu;
m_cpu=NULL;
}
if(m_vc!=NULL)
{
delete m_vc;
m_vc=NULL;
}
if(m_mem!=NULL)
{
delete m_mem;
m_mem=NULL;
}
}
private:
CPU* m_cpu;
VideoCard* m_vc;
Memory* m_mem;
};
class IntelCPU: public CPU
{
public:
virtual void calculate()
{
cout<<"Intel的Cpu开始计算了"<<endl;
}
};
class IntelVideoCard: public VideoCard
{
public:
virtual void display()
{
cout<<"Intel的显卡开始显示了"<<endl;
}
};
class IntelMemory: public Memory
{
public:
virtual void storage()
{
cout<<"Intel的内存条开始存储了"<<endl;
}
};
class LenovoCPU: public CPU
{
public:
virtual void calculate()
{
cout<<"Lenovo的Cpu开始计算了"<<endl;
}
};
class LenovoVideoCard: public VideoCard
{
public:
virtual void display()
{
cout<<"Lenovo的显卡开始显示了"<<endl;
}
};
class LenovoMemory: public Memory
{
public:
virtual void storage()
{
cout<<"Lenovo的内存条开始存储了"<<endl;
}
};
int main()
{
CPU* intelCpu=new IntelCPU;
VideoCard* intelCard=new IntelVideoCard;
Memory* intelMem=new IntelMemory;
Computer* computer1=new Computer(intelCpu,intelCard,intelMem);
computer1->work();
delete computer1;
Computer* computer2=new Computer(new LenovoCPU,new LenovoVideoCard,new LenovoMemory);
computer2->work();
delete computer2;
return 0;
}
程序运行时产生的数据都属于临时数据,程序一旦运行结束都会被释放
通过文件可以将数据持久化
C++中对文件操作需要包含头文件
文件类型分为两种:
1.文本文件 -文本以ASCLL码值的形式存储在计算机中
2.二进制文件 -文件以文本的二进制形式存储在计算机中,用户一般不能直接读懂他们。
ios::in 为读文件而打开文件
ios::out 为写文件而打开文件
ios::ate 初始位置:文件尾
ios::app 追加方式写文件
ios::trunc 如果文件存在先删除,在创建
ios::binary 二进制形式
在当前文件路径下便可以找到存储的内容
#include
#include
using namespace std;
int main()
{
//写文件,将数据存入到磁盘中
ofstream ofs;
ofs.open("test.txt", ios::out);//打开方式
ofs << "姓名:张三" << endl;
ofs << "性别:男" << endl;
ofs.close();
return 0;
}
#include
#include
#include
using namespace std;
int main()
{
//读文件
ifstream ifs;
ifs.open("test.txt", ios::in);
if (!ifs.is_open())
{
cout << "文件打开失败" << endl;
return 0;
}
//第一种
/*char buf[1024] = { 0 };
while (ifs >> buf)
{
cout << buf << endl;
}*/
//第二种
/*char buf[1024] = { 0 };
while (ifs.getline(buf,sizeof(buf)) )
{
cout << buf << endl;
}*/
第三种
//string buf;
//while (getline(ifs, buf))
//{
// cout << buf << endl;
//}
//第三种
char c;
while ((c = ifs.get()) != EOF)
{
cout << c ;
}
//关闭文件
ifs.close();
return 0;
}
#include
#include
#include
using namespace std;
class Person
{
public:
char m_Name[64];
int m_Age;
};
int main()
{
ofstream ofs;
ofs.open("person.txt",ios::out|ios::binary);
Person p={"张三",18};
ofs.write((const char*)&p,sizeof(Person));
ofs.close();
return 0;
}
#include
#include
#include
using namespace std;
class Person
{
public:
char m_Name[64];
int m_Age;
};
int main()
{
ifstream ifs;
ifs.open("person.txt",ios::in|ios::binary);
if(!ifs.is_open())
{
cout<<"文件打开失败"<<endl;
}
Person p;
ifs.read(( char*)&p,sizeof(Person));
cout<<"姓名"<<p.m_Name<<"年龄"<<p.m_Age<<endl;
ifs.close();
return 0;
}