c++面向对象基础学习笔记
#include <iostream>
#include <string>
#include <stdio.h>
#include "demo_a.hpp"
class Person{
public:
//带参构造
Person(std::string name,int age){
this->name = name;
this->age = age;
std::cout << "hello person" << std::endl;
std::cout << "name: " << this->name << std::endl;
}
//拷贝构造
Person(Person &&p1){
this->name = p1.name;
this->age = p1.age;
std::cout << "hello person" << std::endl;
std::cout << "name: " << this->name << std::endl;
}
~Person(){
std::cout << "person died" << std::endl;
}
static void print_ms(){
std::cout << "ms: " << Person::m_s << std::endl;
}
private:
std::string name = "person";
int age = 88;
std::string lover = "kkk";
static int m_s;
};
int Person::m_s = 99;
/******类对象作为类成员******/
class A{
public:
A(){
std::cout << "a的构造" << std::endl;
}
~A(){
std::cout << "a的析构" << std::endl;
}
};
class B{
public:
A a;
B(){
std::cout << "b的构造" << std::endl;
}
~B(){
std::cout << "b的析构" << std::endl;
}
};
/**********this指针***********/
class People{
public:
People(int age){
this->age = age;
std::cout << "hello people" << std::endl;
}
People& add_age(People p){
this->age += p.age;
return *this;
}
public:
int age;
};
/*********空指针测试********/
class Test{
public:
void t_print(){
std::cout << "空指针测试" << std::endl;
}
void t_print_null(){
if(NULL == this){
return;
}
std::cout << "age: " << m_age << std::endl;
}
public:
int m_age = 99;
};
/***********常函数测试**********/
/***********常对象测试**********/
class Test_const{
public:
Test_const(){
}
void t_print() const{
std::cout << "常函数测试" << std::endl;
this->m_b = 90;
}
//常对象不能去调用非const成员函数
/*
void t_print_hello(){
std::cout << "hello" << std::endl;
}
*/
public:
int m_a = 100;
mutable int m_b;
};
/*************友元测试************/
/************全局函数作友元***********/
/***********类作友元**********/
/***************成员函数作友元**************/
class Building;
class Goodguy {
public:
Goodguy();
void vist(Building* b);
void vist2(Building* b);
private:
Building* b;
};
class Building {
//声明全局函数友元
friend void Goodguy_vist(Building* b);
//声明类友元
//friend class Goodguy;
//声明成员函数作友元
friend void Goodguy::vist(Building* b);
public:
Building();
public:
std::string sitting_room;
private:
std::string bedroom;
};
Building::Building(){
this->sitting_room = "客厅";
this->bedroom = "卧室";
}
Goodguy::Goodguy(){
this->b = new Building();
}
void Goodguy_vist(Building* b){
std::cout << "好朋友在拜访:" << b->sitting_room << std::endl;
std::cout << "好朋友在拜访:" << b->bedroom << std::endl;
}
void Goodguy::vist(Building* b){
this->b = b;
std::cout << "goodguy vist: " << this->b->sitting_room << std::endl;
std::cout << "goodguy vist: " << this->b->bedroom << std::endl;
}
void Goodguy::vist2(Building* b){
this->b = b;
std::cout << "goodguy vist2: " << this->b->sitting_room << std::endl;
//std::cout << "goodguy vist2: " << this->b->bedroom << std::endl;
}
/***********运算符重载**********/
//1.成员函数重载运算符
//2.全局函数重载运算符
/**************加号运算符重载************/
class Num{
public:
Num(int a,int b);
Num operator+(const Num& n);
//运算符重载实现自增运算符,前置++
Num& operator++(){
this->m_a++;
this->m_b++;
return *this;
}
//运算符重载实现自增运算,后置++
Num operator++(int){
Num temp = *this;
this->m_a++;
this->m_b++;
return temp;
}
public:
int m_a;
int m_b;
//friend std::ostream& operator>>(std::ostream& in,Num &n);
};
Num::Num(int a,int b){
this->m_a = a;
this->m_b = b;
}
/*
//成员函数实现运算符重载
Num Num::operator+(const Num& n){
Num temp(10,20);
temp.m_a = this->m_a + n.m_a;
temp.m_b = this->m_b + n.m_b;
return temp;
}
//全局函数方式实现运算符重载
Num operator+(Num& n1,int val){
Num temp(10,20);
temp.m_a = n1.m_a + val;
temp.m_b = n1.m_b + val;
return temp;
}
*/
/*
//全局函数方式实现<<左移运算符重载 --- 实现左移运算符输出自定义数据类型
std::ostream& operator<<(std::ostream& out,Num &n){
out << "a: " << n.m_a << " b: " << n.m_b << std::endl;
return out;
}
*/
/*
//全局函数的方式实现>>右移运算符重载 --- 实现右移
std::istream& operator>>(std::istream& in,Num &n){
in >> n.m_a >> n.m_b;
return in;
}
*/
//赋值运算符重载
class Someone{
public:
Someone(int age){
//堆区申请空间
this->m_age = new int(age);
}
//赋值运算符重载
Someone& operator=(Someone& p){
if(NULL != this->m_age){
delete this->m_age;
this->m_age = NULL;
}
//深拷贝
this->m_age = new int(*p.m_age);
return *this;
}
~Someone(){
if(NULL != this->m_age){
delete this->m_age;
this->m_age = NULL;
}
}
public:
int *m_age;
};
//关系运算符重载
class Human{
public:
Human(std::string name,int age){
this->name = name;
this->age = age;
}
~Human(){
std::cout << "human died" << std::endl;
}
//==运算符重载
bool operator==(Human& h){
if(this->name == h.name && this->age == h.age){
return true;
}
else{
return false;
}
}
//!=运算符重载
bool operator!=(Human& h){
if(this->name != h.name || this->age != h.age){
return true;
}
else{
return false;
}
}
public:
std::string name;
int age;
};
//函数调用()运算符重载(仿函数)
//仿函数实现输出打印
class M_print{
public:
void operator()(std::string txt){
std::cout << txt << std::endl;
}
};
//仿函数实现两数相加的功能
class M_add{
public:
int operator()(int a,int b){
int temp = a + b;
return temp;
}
};
/***********继承**********/
class Father{
public:
Father(){
std::cout << "father is birth" << std::endl;
}
~Father(){
std::cout << "father is dead" << std::endl;
}
};
class Son:public Father{
public:
Son(){
std::cout << "son is birth" << std::endl;
}
~Son(){
std::cout << "son is dead" << std::endl;
}
};
//菱形继承:
//动物
class Ani{
public:
int m_a;
};
//羊
class Sheep:virtual public Ani{};
//驼
class Tuo:virtual public Ani{};
//羊驼
class SheepTuo:public Sheep,public Tuo{};
int& test(){
static int a = 99;
return a;
}
/***********多态**********/
class Dw{
public:
virtual void speak(){
std::cout << "动物在说话" << std::endl;
}
};
class Cat:public Dw{
public:
void speak(){
std::cout << "猫在说话" << std::endl;
}
};
class Dog:public Dw{
public:
void speak(){
std::cout << "狗在说话" << std::endl;
}
};
void Dw_speak(Dw& d){
d.speak();
}
const int My::a;
struct Joker{
//public:
Joker(){
std::cout << "joker is born" << std::endl;
}
~Joker(){
std::cout << "joker is dead" << std::endl;
}
};
int main()
{
Father* p = new Son();
/*
//匿名对象调用
std::cout << M_add()(80,90) << std::endl;
M_print()("hello c++");
*/
return 0;
}
//注意:
//在cin和scanf中遇到空格,制表符,回车时会自动结束
//getline读取一行,可以读取到空格和回车符
//设计策略:
/*
面向对象的系统可能会使用一个抽象基类为外部应用程序提供适当的、通用的、标准化的接口
*/
//::的作用:
//1. 作用域解析符:用于限定作用域,访问命名空间中的变量和函数
//2. 类型修饰符:用于修饰类型,声明指针,引用,函数返回值类型等
//3. 静态成员访问符:用于访问类的静态成员变量和静态成员函数
//4. 全局作用域:表示全局命名空间,可以访问全局变量和全局函数
//5. 类作用域:表示当前类的命名空间,可以访问类的成员变量和成员函数
//6. 命名空间作用域:表示命名空间的命名空间,可以访问命名空间中的变量和函数
//面向对象中,对象间的几大关系:
//1. 依赖关系: 类A依赖于类B,表示类A使用了类B的功能,类A不能单独存在,必须依赖于类B
//2. 关联关系: 类A关联于类B,表示类A和类B有关联,类A和类B可以单独存在,也可以同时存在
//3. 聚合关系: 类A聚合类B,表示类A和类B有包含关系,类A的生命周期依赖于类B的生命周期,当类A被销毁时,类B也会被销毁
//4. 组合关系: 类A组合类B,表示类A和类B有整体和部分的关系,类A的生命周期和类B的生命周期是一致的,当类A被销毁时,类B也会被销毁
//5. 继承关系: 类A继承类B,表示类A和类B有相同的属性和方法,类A可以单独存在,也可以同时存在,类A称为子类,类B称为父类
//struct默认权限为public
//class默认权限为private
//在class中包括构造函数和析构函数,若不加以权限描述,则默认权限为private
//引用:
//左值引用和右值引用:
//Person &a --- 左值引用,是用来指向已经存在对象的引用
//Person &&a --- 右值引用,用来指向临时对象的引用
//构造和析构:
//默认构造:无参数,函数体为空
//默认析构:无参数,函数体为空
//默认拷贝构造:拷贝属性值
//相关规则:
//只定义有参构造,则默认不提供无参构造
//只定义拷贝构造,则默认不提供其他构造
//初始化列表:
/*
构造函数():属性1(值1),属性2(值2),属性3(值3),...{}
*/
//调用顺序:
//1.基类
//2.成员类
//3.派生类
//虚析构:
//解决父类指针去释放子类对象的问题
//深浅拷贝:
//深拷贝:在堆区申请空间,再赋值
//浅拷贝:直接赋值
//初始化列表语句
//Person(int a,int b,int c):m_a(a),m_b(b),m_c(c){}
//类对象作为类成员
//当有类对象作为成员时
//构造函数和析构函数的调用顺序:
//先调用成员对象的构造,再调用对象的构造
//先调用对象的析构,再调用成员对象的析构
//静态成员:
//所有对象共享一份数据(静态成员属于类本身,而不属于类的实例)
//类内声明,类外初始化
//在编译阶段分配内存
//静态成员函数只能去访问静态成员变量,this指针在静态成员函数中无法调用
//空指针时可以去调用成员函数的,在没有涉及到this指针的情况下(即没有涉及到成员变量的操作)
//const成员函数 --- 常函数
//常函数的定义方法: --- 函数定义的名字的括号后面加上const关键字
//常函数不能去修改成员变量
//常函数若想去修改成员变量,则必须在修改的成员变量前加上mutable关键字
//const对象 --- 常对象
//常对象只能调用常函数
//常对象不能修改成员变量
//常对象只能修改有mutable关键字修饰的成员变量
//常对象不能调用非const成员函数
//内联函数:
//inline关键字声明:
//在类中定义函数默认为内联函数
//在类外定义函数默认为普通函数
//在类外定义inline函数,必须在函数定义前加上inline关键字
//注意:内联函数在编译时直接展开,效率高,但过多的内联会导致代码膨胀,增加编译时间,应谨慎使用
//实际上就是以空间换时间
//推荐:在函数短小的时候使用内联函数.........函数过长或复杂时或递归调用时,不建议使用内联函数,会是代码膨胀
//运算符重载:
//对已有的运算符进行重新定义,赋予其另一种功能,以实现不同数据类型的运算
//继承:
//在继承关系下,派生类在实例化时,总是先调用基类的构造函数,再调用派生类的构造函数
//再进行析构时,则是先调派生类的析构,再去调用基类的析构
//继承关系下,成员的访问:
//父类与子类有相同名字的成员,子类在访问时,直接访问即可
//子类访问父类的同名成员,需要加上父类的作用域
//菱形继承:
//例子:羊继承了动物的属性,驼也继承了动物的属性,羊驼继承了羊和驼的属性,这就是菱形继承
//产生的问题,羊驼都继承了动物的属性,在羊驼使用时,就会产生二义性
//数据继承了两份,只需要一份即可
//解决方法:采用虚继承
//注意:
//以下几点派生类无法继承基类:
//基类的重载运算符
//基类的友元函数
//纯虚函数必须为virtual xxx(xxx) = 0;
//若声明为virtual xxx(xxx){},则不是纯虚函数,该函数函数实现为空,而虚函数没有函数实现
//多态:
//静态多态:函数重载、运算符重载,复用函数名
//动态多态:派生类和虚函数实现运行时多态
//多态满足的条件:
//有继承关系
//子类重写父类中的虚函数
//多态发生的条件:
//父类指针或饮用指向子类对象
//多态的几大特点:
//虚函数:
//在基类中virtual声明一个函数
//派生类可以重写(override)这个函数
//调用虚函数时,根据实际对象来决定调用哪个版本
//动态绑定:
//也称为晚期绑定,运行时确定函数的具体实现
//需要使用基类指针或引用来调用虚函数,根据具体对象来调用函数
//纯虚函数:
//一个包含纯虚函数的类,不能被实例化,称为抽象类
//纯虚函数没有函数体, = 0
//强制派生类提供具体实现 --- 否则派生继承基类的纯虚函数,也成为了抽象类,无法实例化
//在继承多个纯虚函数的情况下,派生类要实现所有的纯虚函数
//具体类:
//可用于实例化对象的类被称为具体类
//数据抽象:
//将具体实现和相关数据分离
//在hal层实现中,头文件和.cpp文件的用途不同,虽然在头文件和.cpp文件中可能都有某一个类的定义
//.cpp文件并没有包含定义向同类的俄头文件,这样不会产生重定义
//问题:
//1.深浅拷贝
//2.内联函数
//3.引用
//引用其实就是给一个变量取别名,打印引用地址,和原变量地址,两者相同
//引用定义时,必须初始化,且一旦初始化,引用值就无法改变了
//引用作为函数的返回值 --- 不要去返回局部变量,函数执行完毕后,局部变量直接销毁,返回个锤子
//想要返回函数中的局部变量,可以通过static声明为静态变量,然后返回引用,其生命周期为整个程序