面向对象基础
#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
using namespace std;
#include <string>
//设计一个类,求圆的周长
const double PI = 3.14;
//class + 类名
//周长公式 : 2 * pi * m_R
class Circle
{
public: //公共权限
//类中的函数 称为 成员函数 成员方法
//求圆周长
double calculateZC() const
{
return 2 * PI * m_R;
}
//设置半径
void setR(int r)
{
m_R = r;
}
//获取半径
int getR() const
{
return m_R;
}
//类中的变量 称为成员变量 成员属性
//半径
int m_R;
};
void test01()
{
Circle c1; //通过类 创建一个对象 实例化对象
//给c1 半径赋值
//c1.m_R = 10;
c1.setR(10);
//求c1圆周长
cout << "圆的半径为: " << c1.getR() << endl;
cout << "圆的周长为: " << c1.calculateZC() << endl;
c1.setR(20);
//求c1圆周长
cout << "圆的半径为: " << c1.getR() << endl;
cout << "圆的周长为: " << c1.calculateZC() << endl;
}
//2 设计一个学生类,属性有姓名和学号,可以给姓名和学号赋值,可以显示学生的姓名和学号
class Student{
public:
//设置姓名
void setName(string name){
m_Name = name;
};
void setId(int id){
m_Id = id;
}
//显示学生信息
void showStudent(){
cout << "姓名:" << m_Name << " 学号: " << m_Id << endl;
}
// 属性
//姓名
string m_Name;
//学号
int m_Id;
};
void test02()
{
Student s1;
s1.m_Name = "张三";
s1.m_Id = 1;
cout << "姓名:" << s1.m_Name << " 学号: " << s1.m_Id << endl;
Student s2;
s2.setName("李四");
s2.setId(2);
s2.showStudent();
Student s3;
s3.setName("王五");
s3.setId(3);
s3.showStudent();
}
int main(){
test01();
test02();
system("pause");
return EXIT_SUCCESS;
}
内联函数
#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
using namespace std;
//宏缺陷1 : 必须要加括号保证运算完整
#define MYADD(x,y) ((x) +(y))
void test01()
{
int a = 10;
int b = 20;
int ret = MYADD(a, b) * 20;
cout << ret << endl;
}
//宏缺陷2: 即使加了括号,有些运算依然与预期不符
#define MYCOMPARE(a,b) (((a) < (b)) ? (a) : (b))
//普通函数 不会出现与预期结果不符的问题
void myCompare(int a, int b)
{
int ret = a < b ? a : b;
cout << "ret = " << ret << endl;
}
void test02()
{
int a = 10;
int b = 20;
myCompare(++a, b);
//int ret = MYCOMPARE(++a, b); //预期是 11 结果变为12 (((++a) < (b)) ? (++a) : (b))
//cout << "ret = " << ret << endl;
}
//内联函数
//函数的声明和实现必须同时加关键字 inline 才算内联函数
//内联函数 好处 :解决宏缺陷,本身是一个函数,带来宏优势,以空间换时间,在适当的时候做展开
inline void func();
inline void func(){};
//类内部的成员函数 在函数前都隐式加了关键字 inline
int main(){
test01();
test02();
system("pause");
return EXIT_SUCCESS;
}
函数的默认参数何占位参数
#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
using namespace std;
//默认参数 语法 形参 类型 变量 = 默认值
//注意事项 ,如果有一个位置有了默认参数,那么从这个位置起,从左到右都必须有默认值
int func(int a, int b = 10 , int c = 10)
{
return a + b + c;
}
void test01()
{
cout << func(20 , 10) << endl;
}
//函数的声明和实现 只能有一个 提供默认参数,不可以同时加默认参数
void myFunc(int a = 10, int b = 10);
void myFunc(int a , int b){};
//占位参数 只写一个类型进行占位,调用时候必须要传入占位值
//占位参数 用途? 目前没用
void func2(int a , int = 1,int =2)
{
}
void test02()
{
func2(10);
}
int main(){
test01();
system("pause");
return EXIT_SUCCESS;
}
函数重载
#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
using namespace std;
//函数重载条件
//1、在同一个作用域
//2、函数名称相同
//3、参数个数、类型、顺序不同
//class Person
//{
//public:
// void func() 成员函数 而不是全局函数
// {
// }
//};
void func()
{
cout << "func()调用" << endl;
}
void func(int a)
{
cout << "func(int a)调用" << endl;
}
void func(double a)
{
cout << "func(double a)调用" << endl;
}
void func(int a, double b)
{
cout << "func(int a ,double b)调用" << endl;
}
void func(double a, int b)
{
cout << "func(double a, int b)调用" << endl;
}
//返回值可不可以作为函数重载的条件 答案:不可以
//int func(int a, double b)
//{
// cout << "func(int a ,double b)调用" << endl;
//}
void test01()
{
func(1.0,3);
}
//函数重载中 引用两个版本
//void myFunc(int a)
//{
// cout << "myfunc(int a )调用" << endl;
//}
void myFunc(int &a) // int & a = 10;
{
cout << "myfunc(int &a )调用" << endl;
}
void myFunc(const int &a) // const int &a = 10;
{
cout << "myfunc( const int &a )调用" << endl;
}
void test02()
{
int a = 10;
//myFunc(a);//需要避免二义性出现
}
//函数重载碰到默认参数 注意避免二义性出现
void func2(int a , int b = 10)
{
}
void func2(int a)
{
}
void test03()
{
//func2(10); //出现二义性
}
int main(){
test01();
test02();
system("pause");
return EXIT_SUCCESS;
}
c语言的封装C
#include <iostream>
#include <cstring>
using namespace std;
struct Person
{
char name[64];
int age;
};
struct Dog
{
char name[64];
int age;
};
void DogEat(struct Dog * dog)
{
printf("%s在吃狗粮\n", dog->name);
}
void PersonEat(struct Person * p)
{
printf("%s在吃人饭\n",p->name);
}
void test01()
{
struct Person p{};
printf("%s\n",p.name);
strcpy(p.name, "张三");
p.age = 10;
PersonEat(&p);
}
int main(){
test01();
return EXIT_SUCCESS;
}
C++的封装
#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
#include <cstring>
using namespace std;
struct Person
{
//公共权限
public:
char name[64];
int age;
void PersonEat()
{
printf("%s在吃人饭\n", name);
}
};
struct Dog
{
//公共权限
public:
char name[64];
int age;
void DogEat()
{
printf("%s在吃狗粮\n", name);
}
};
//C++封装 理念: 将属性和行为作为一个整体,来表现生活中的事物
//第二次理念: 将属性和行为 加以权限控制
void test01()
{
struct Person p;
strcpy(p.name, "老王");
p.PersonEat();
//p.DogEat();
}
//struct和class 区别?
//class 默认权限 私有权限 而 struct默认权限是 公共权限
//访问权限
// public 公共权限 成员 类内 类外 都可以访问
// private 私有权限 成员 类内 可以访问 类外 不可以访问 儿子不可以访问父亲的private权限内容
// protected 保护权限 成员 类内 可以访问 类外 不可以访问 儿子可以访问父亲的protected权限内容
class Person2
{
public:
string m_Name; //公共权限
protected:
string m_Car; //保护权限
private:
int m_pwd; //私有权限
public:
void func()
{
m_Name = "张三";
m_Car = "拖拉机";
m_pwd = 123456;
}
};
void test02()
{
Person2 p;
p.m_Name = "李四"; //公共权限 类外可以访问
// p.m_Car = "劳斯莱斯"; //保护权限 类外访问不到
// p.m_pwd = 123; //私有权限 类外不可以访问
}
int main(){
test01();
system("pause");
return EXIT_SUCCESS;
}
示例2
#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
using namespace std;
#include <string>
class Person
{
public:
//设置姓名
void setName(string name)
{
m_Name = name;
}
//获取姓名
string getName()
{
return m_Name;
}
//获取年龄
int getAge()
{
return m_Age;
}
//设置年龄
void setAge(int age)
{
if ( age < 0 || age > 150)
{
cout << "你这个老妖精" << endl;
return;
}
m_Age = age;
}
//设置情人
void setLover(string lover)
{
m_Lover = lover;
}
private:
string m_Name; //姓名 可读可写
int m_Age = 18; //年龄 可读 可写(0 ~ 150之间)
string m_Lover; //情人 只写
};
void test01()
{
Person p;
//可以将char * 隐式类型转换为 string
p.setName("张三");
cout << "姓名: " << p.getName() << endl;
//获取年龄
p.setAge(100);
cout << "年龄: " << p.getAge() << endl;
//设置情人
p.setLover("苍井");
//cout << "张三情人是:"<< p.m_Lover <<endl; //情人是只写权限 外部访问不到
}
//将成员属性都设置为私有好处:自己可以控制读写权限
//可以对设置内容 加有效性验证
int main(){
test01();
system("pause");
return EXIT_SUCCESS;
}
#include <iostream>
using namespace std;
class Cube{
public:
void setL(int L){
this->m_L = L;
}
void setW(int W){
this->m_W = W;
}
void setH(int H){
this->m_H = H;
}
int getL(){
return this->m_L;
}
int getW(){
return this->m_W;
}
int getH(){
return this->m_H;
}
//求面积
int calculateS()
{
return 2 * m_L*m_W + 2 * m_W*m_H + 2 * m_L*m_H;
}
//求体积
int calculateV()
{
return m_L * m_W * m_H;
}
int m_L,m_W,m_H;
//利用成员函数 判断立方体是否相等
bool compareCubeByClass( Cube &c )
{
return this->m_L == c.getL() && this->m_W == c.getW() && this->m_H == c.getH();
}
};
bool compareCube(Cube &c1,Cube &c2)
{
return c1.m_L == c2.getL() && c1.m_W == c2.getW() && c1.m_H == c2.getH();
}
void test01(){
Cube c1;
c1.setL(10);
c1.setW(10);
c1.setH(10);
cout << "c1面积为: " << c1.calculateS() << endl; //600
cout << "c1体积为: " << c1.calculateV() << endl; //1000
Cube c2;
c2.setL(10);
c2.setW(10);
c2.setH(10);
//利用全局函数判断 c1 和 c2是否相等
bool ret = compareCube(c1, c2);
if (ret)
{
cout << "c1 与 c2 相等" << endl;
}
else
{
cout << "c1 与 c2 不相等" << endl;
}
//利用成员函数 判断 c1 和 c2是否相等
ret = c1.compareCubeByClass(c2);
if (ret)
{
cout << "成员函数判断:c1 与 c2 相等" << endl;
}
else {
cout << "成员函数判断:c1 与 c2"<<endl;
}
};
int main(){
test01();
system("pause");
return EXIT_SUCCESS;
}
全局函数与析构函数
#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
using namespace std;
class Person{
public: //构造和析构必须要声明在全局作用域
//构造函数
//没有返回值 不用写void
//函数名 与 类名相同
//可以有参数 ,可以发生重载
//构造函数 由编译器自动调用一次 无须手动调用
Person(){
cout<<"析构函数调用!"<<endl;
}
//析构函数
//没有返回值 不用写void
//函数名 与类名相同 函数名前 加 ~
//不可以有参数 ,不可以发生重载
//析构函数 也是由编译器自动调用一次,无须手动调用
~Person()
{
cout << "Person的析构函数调用" << endl;
}
};
int main(){
Person p;
return EXIT_SUCCESS;
}
析构函数分类以及调用
#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
using namespace std;
class Person{
public: //构造和析构必须要声明在全局作用域
//构造函数
//没有返回值 不用写void
//函数名 与 类名相同
//可以有参数 ,可以发生重载
//构造函数 由编译器自动调用一次 无须手动调用
Person(){
cout<<"构造函数调用!"<<endl;
}
Person(int age){
cout<<"有参数构造函数调用!"<<endl;
m_Age = age;
}
Person(const Person &p){
cout<<"拷贝构造函数调用!"<<endl;
m_Age = p.m_Age;
}
//析构函数
//没有返回值 不用写void
//函数名 与类名相同 函数名前 加 ~
//不可以有参数 ,不可以发生重载
//析构函数 也是由编译器自动调用一次,无须手动调用
~Person()
{
cout << "Person的析构函数调用" << endl;
}
private:
int m_Age;
};
int main(){
//Person p;
//1、括号法
//Person p1(10);
//Person p2(p);
//注意事项一
//不要用括号法 调用无参构造函数 Person p3(); 编译器认为代码是函数的声明
//2、显示法
//Person p3 = Person(10); //有参构造
//Person p4 = Person(p3); //拷贝构造
//Person(10); //匿名对象 特点: 当前行执行完后 立即释放
//cout << "aaa" << endl;
//注意事项二
//不要用拷贝构造函数 初始化 匿名对象 Person(p3); 编译器认为 Person p3对象实例化 如果已经有p3 p3就重定义
Person p;
Person p2(10);
Person p3(p2);
return EXIT_SUCCESS;
}
拷贝构造函数调用
#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
using namespace std;
class Person{
public: //构造和析构必须要声明在全局作用域
//构造函数
//没有返回值 不用写void
//函数名 与 类名相同
//可以有参数 ,可以发生重载
//构造函数 由编译器自动调用一次 无须手动调用
Person(){
cout<<"构造函数调用!"<<endl;
}
Person(int age){
cout<<"有参数构造函数调用!"<<endl;
m_Age = age;
}
Person(const Person &p){
cout<<"拷贝构造函数调用!"<<endl;
m_Age = p.m_Age;
}
//析构函数
//没有返回值 不用写void
//函数名 与类名相同 函数名前 加 ~
//不可以有参数 ,不可以发生重载
//析构函数 也是由编译器自动调用一次,无须手动调用
~Person()
{
cout << "Person的析构函数调用" << endl;
}
int m_Age;
};
//1、用已经创建好的对象来初始化新的对象
void test01()
{
Person p1(18);
Person p2 = Person(p1);
cout << "p2的年龄:" << p2.m_Age<< endl;
}
//2、值传递的方式 给函数参数传值
void doWork(Person p)
{
}
void test02()
{
Person p1(100);
doWork(p1);
}
//3、以值方式 返回局部对象
Person doWork2()
{
Person p;
return p;
}
void test03()
{
printf("test03\n");
Person p = doWork2();
printf("test03结束\n");
}
/*
编译器优化代码后 release版本代码类似以下:
void doWork2( Person &p ){};
Person p;
doWork2(p);
*/
int main(){
test01();
test02();
test03();
system("pause");
return EXIT_SUCCESS;
}
构造函数的调用规则
#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
using namespace std;
class Person{
public: //构造和析构必须要声明在全局作用域
//构造函数
//没有返回值 不用写void
//函数名 与 类名相同
//可以有参数 ,可以发生重载
//构造函数 由编译器自动调用一次 无须手动调用
Person(){
cout<<"构造函数调用!"<<endl;
}
Person(int age){
cout<<"有参数构造函数调用!"<<endl;
m_Age = age;
}
Person(const Person &p){
cout<<"拷贝构造函数调用!"<<endl;
m_Age = p.m_Age;
}
//析构函数
//没有返回值 不用写void
//函数名 与类名相同 函数名前 加 ~
//不可以有参数 ,不可以发生重载
//析构函数 也是由编译器自动调用一次,无须手动调用
~Person()
{
cout << "Person的析构函数调用" << endl;
}
int m_Age;
};
//1、用已经创建好的对象来初始化新的对象
void test01()
{
Person p1(18);
Person p2 = Person(p1);
cout << "p2的年龄:" << p2.m_Age<< endl;
}
//2、值传递的方式 给函数参数传值
void doWork(Person &p)
{
}
void test02()
{
Person p1(100);
doWork(p1);
}
//3、以值方式 返回局部对象
Person doWork2()
{
Person p;
return p;
}
void test03()
{
printf("test03\n");
Person p = doWork2();
printf("test03结束\n");
}
/*
编译器优化代码后 release版本代码类似以下:
void doWork2( Person &p ){};
Person p;
doWork2(p);
*/
int main(){
test01();
test02();
test03();
system("pause");
return EXIT_SUCCESS;
}
构造函数调用规则
#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
using namespace std;
//1、编译器会给一个类 至少添加3个函数 默认构造(空实现) 析构函数(空实现) 拷贝构造(值拷贝)
//2、如果我们自己提供了 有参构造函数,编译器就不会提供默认构造函数,但是依然会提供拷贝构造函数
//3、如果我们自己提供了 拷贝构造函数,编译器就不会提供其他构造函数
class Person{
public:
explicit Person(){
cout<<"默认构造函数调用"<<endl;
}
explicit Person(int age){
m_Age = age;
cout<<"拷贝构造函数调用"<<endl;
}
~Person(){
cout<<"析构函数调用"<<endl;
}
int m_Age{};
};
void test01(){
Person p1; //提供拷贝构造后,要自己提供默认构造
p1.m_Age = 20;
Person p2(p1);
Person P3(20);
cout<<"p2的年龄为:"<<p2.m_Age<<endl;
}
int main(){
test01();
system("pause");
return EXIT_SUCCESS;
};
深拷贝浅拷贝
#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
#include <cstring>
using namespace std;
class Person{
public:
explicit Person(char *name,int age){
m_Name = (char *) malloc(strlen(name)+1);
strcpy(m_Name,name);
m_Age = age;
}
explicit Person(const Person &p){
m_Name = (char *) malloc(strlen(p.m_Name)+1);
strcpy(m_Name,p.m_Name);
m_Age = p.m_Age;
}
char *m_Name;
int m_Age;
};
void test01(){
Person p("德玛西亚",18);
cout << "姓名: " << p.m_Name << " 年龄: " << p.m_Age << endl;
Person p2(p);
cout << "姓名: " << p.m_Name << " 年龄: " << p.m_Age << endl;
};
int main(){
test01();
system("pause");
return EXIT_SUCCESS;
}
初始化列表
#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
using namespace std;
class Person
{
public:
//Person(int a, int b, int c)
//{
// m_A = a;
// m_B = b;
// m_C = c;
//}
//Person() :m_A(10), m_B(20), m_C(30)
//{
//}
//构造函数名称后 : 属性(值), 属性(值)...
Person(int a, int b, int c) : m_A(a), m_B(b), m_C(c)
{
}
int m_A;
int m_B;
int m_C;
};
void test01()
{
Person p(10, 20, 30);
cout << "m_A = " << p.m_A << endl;
cout << "m_B = " << p.m_B << endl;
cout << "m_C = " << p.m_C << endl;
}
int main(){
test01();
system("pause");
return EXIT_SUCCESS;
}
类对象作为类成员
- 自下而上,自上而下
#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
using namespace std;
#include <string>
#include <utility>
class Phone
{
public:
Phone(string pName)
{
cout << "phone 的有参构造调用" << endl;
m_PhoneName = pName;
}
~Phone()
{
cout << "phone 的析构函数调用" << endl;
}
string m_PhoneName;
};
class Game
{
public:
Game(string gName)
{
cout << "Game 的有参构造调用" << endl;
m_GameName = gName;
}
~Game()
{
cout << "Game 的析构函数调用" << endl;
}
string m_GameName;
};
class Person
{
public:
Person(string name, string pName, string gName) : m_Name(std::move(name)), m_Phone(std::move(pName)), m_Game(std::move(gName))
{
cout << "Person 的有参构造调用" << endl;
}
void PlayGame() const
{
cout << m_Name << "拿着 << " << m_Phone.m_PhoneName << " >> 牌手机,玩着 :" << m_Game.m_GameName << endl;
}
~Person()
{
cout << "Person 的析构函数调用" << endl;
}
string m_Name; //姓名
Phone m_Phone; //手机
Game m_Game; //游戏
};
void test01()
{
//当其他类对象 作为本类成员,先构造其他类对象,再构造自身,析构的顺序和构造相反
Person p("张三", "苹果", "王者荣耀");
p.PlayGame();
Person p2("李四", "三星", "消消乐");
p2.PlayGame();
}
int main(){
test01();
system("pause");
return EXIT_SUCCESS;
}
explict 关键字的作用
#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
using namespace std;
class MyString
{
public:
MyString(char * str)
{
}
//explicit用途: 防止利用隐式类型转换方式来构造对象
explicit MyString(int len)
{
}
};
void test01()
{
MyString str1(10);
MyString str2 = MyString(100);
//MyString str3 = 10; // "10"
}
int main(){
test01();
system("pause");
return EXIT_SUCCESS;
}
malloc 和new 的区别
#include <iostream>
using namespace std;
class Person{
public:
Person(){
cout << "Person构造函数调用" << endl;
}
Person(int a){
cout << "Person有参数构造函数调用" << endl;
}
~Person(){
cout << "Person析构函数调用" << endl;
}
};
//malloc 和 new 区别
//malloc 和 free 属于 库函数 new 和delete属于 运算符
//malloc不会调用构造函数 new会调用构造函数
//malloc返回void* C++下要强转 new 返回创建的对象的指针
void test01(){
Person *p = new Person;
delete p;
};
// 注意事项 不要用void*去接受new出来的对象,利用void*无法调用析构函数
void test02(){
void *p = new Person;
delete p ;
}
void test03(){
// int *pInt = new int[10];
// double *pDouble = new double[10];
// Person *pperson = new Person[10];
//
// delete[] pperson;
//栈上开辟数组,可不可以没有默认构造,可以没有默认构造
Person pArray[10] = {
Person(10),
Person(20),
Person(20)
};
}
int main(){
// test01();
// test02();
test03();
return EXIT_SUCCESS;
}