对象的初始化和清理
对象的初始化和清理
c++利用构造函数和析构函数
深拷贝:简单的赋值拷贝操作
浅拷贝:在堆区重新申请空间,进行拷贝操作
m_Height=p.m_Height
m_Height = new int(*p.m_Height)
初始化列表:
语法:构造函数():属性1(值1),属性2(值2),属性3(值3)...{}
示例:
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){}
类对象作为类成员
class A{}
class B{
A a;
}
静态成员函数
所有对象共享同一个函数
静态成员函数只能访问静态成员变量
class Person{
public:
m_A=100;
static void func(){
cout<<""<<end;
}
static int m_A;
}
int Person::m_A=0;
void test01(){
Person p;
p.func();
Person::func();
}
c++对象模型和this指针
成员变量和成员函数分开存储
只有非静态成员变量才属于类的对象
this指针概念
每一个非静态成员变量只会诞生一份函数实例,也就是说多个同类型的对象会共用一块代码
C++通过提供特殊对象,this指针,解决上述问题,this指针指向被调用的成员函数所属的对象
this指针是隐含每一个非静态成员函数内的一种指针
this指针不需要定义,直接使用即可
this指针的用途:
当形参和成员函数同名时,可用this指针来区分
在类的非静态成员函数中返回对象本身,可使用return *this
class Person{
public:
Person(int age){
this->age=age;
}
int age;
};
void test(){
Person p1(18);
}
public:
Person(int age){
this->age=age;
}
Person& PersonAddAge(Person &p){
this->age += p.age;
return *this;
}
int age;
};
void test(){
Person p1(10);
Person p2.PersonAddAge(p1).PersonAddAge(p1).PersonAddAge(p1);
}
空指针访问成员函数
class Person{
public:
void showClassName(){
}
void showPersonAge(){
}
};
void test01(){
Person *p=NULL;
p->showClassName();
}
const修饰成员函数
常函数:
成员函数加const后我们称为这个函数的常函数
常函数内不可以修改成员属性
成员属性声明时加关键字mutable,在常函数中依次可以修改
常对象:
声明对象前加const称为该对象为常函数
常对象只能调用常函数
this->m
mutable int m;
常对象:
void test02(){
const Person p;
}
友元
friend void goodGay(Building *building);
friend class className;
做友元可以访问私有属性
运算符重载:
运算符重载概念:对已有的运算符重新进行定义,赋予其另一种功能,以适应不同的数据类型
对于内置的数据类型,编译器如何进行运算:
int a = 10
int b = 10
int c = a*b
继承
语法:class 子类:public(继承方式) 父类{};
class BasePage{};
class Java:public BasePage{
public:
}
子类也叫派生类,父类也叫基类
protected继承可以访问
继承方式:
公共继承:public
保护继承:protected
私有继承:private
继承中对象模型
cl /d1 reportSingleClassLayoutSon name.cpp
继承中构造和析构顺序
顺序:父类构造,子类构造,子类析构,父类析构
继承同名成员处理方式
访问子类同名成员,直接访问即可
访问父类同名成员,需要加作用域: 父类::属性
作用域就是::
同名成员函数怎么处理
也是加作用域
继承中同名静态成员处理方式
静态和非静态出现同名,处理方式一样
访问子类同名,直接访问
访问父类同名成员,加作用域
{
public:
static int m_A;
}
int Base::m_A=100;
多继承语法:
class 子类:继承方式 父类1,继承方式 父类2...
class Son:public Base1, public Base2{
public:
Son()
}
菱形继承:
动物 羊 驼 羊驼
羊继承动物
驼继承动物
羊驼继承羊和驼 叫做菱形继承或者叫钻石继承
多继承会产生二义性
羊驼会继承两份,其实我们应该清楚,这份数据我们只需要一份就可以了
class Animal {
public:
int m_Age;
};
class Sheep:virtual public Animal {
};
class Tuo :virtual public Animal {
};
class SheepTuo :public Sheep, public Tuo {
};
全部变成了一个
void test02() {
SheepTuo st;
st.Sheep::m_Age=18;
st.Tuo::m_Age = 28;
cout << st.Sheep::m_Age << endl;
cout << st.Tuo::m_Age << endl;
cout << st.m_Age << endl;
}
vbptr:virtual base pointer 虚基类指针指向vbtable,指向一个虚基类表
记住的是指针,第二个指针继承第二个数字
多态
多态是c++面向对象三大特征之一
静态多态:函数重载和运算符重载属于静态多态,复合函数名
动态多态:派生类和虚函数实现运行时多态
区别:
静态多态的函数地址早绑定-编译阶段确定函数地址
动态多态的函数地址晚绑定-运行阶段确定函数地址
class Animal {
public:
virtual void speak() {
cout << "动物在说话" << endl;
}
};
class Cat:public Animal {
public:
void speak() {
cout << "小猫在说话" << endl;
}
};
void doSpeak(Animal &animal) {
animal.speak();
}
void test01() {
Cat cat;
doSpeak(cat);
}
int main() {
test01();
动态多态满足条件:
1.有继承关系
2.子类要重写父类的虚函数
3.父类的指针或者引用,执行子类对象
多态深入解剖
动态多态:
静态多态:
vfptr:virtual function pointer:虚函数指针
虚函数地址:
&Animal::speak
多态的好处:
组织结构清晰
易扩展
class AbstractCalculator{
public:
virtual int getResult() {
return 0;
}
int m_Num1;
int m_Num2;
};
class AddCalculator :public AbstractCalculator {
public:
int getResult() {
return m_Num1 + m_Num2;
}
};
class SubCalculator :public AbstractCalculator {
public:
int getResult() {
return m_Num1 - m_Num2;
}
};
class MulCalculator :public AbstractCalculator {
public:
int getResult() {
return m_Num1 * m_Num2;
}
};
void test02() {
AbstractCalculator *abc= new AddCalculator;
abc->m_Num1 = 10;
abc->m_Num2 = 10;
cout << abc->m_Num1 << "+" << abc->m_Num2 << "=" << abc->getResult() << endl;
delete abc;
}
纯虚函数和抽象类
在多态中,通常父类的虚函数的实现中毫无意义,主要是调用子类重写的内容
因此可以改写为纯虚函数
纯虚函数:virtual 返回值类型 函数名 (参数列表)=0;
单类中有纯虚函数,这个类也称抽象类
抽象类:
无法实例化对象
子类必须重写类中的纯虚函数,否则也属于抽象类
class Base {
public:
virtual void func() = 0;
};
class Son :public Base {
public:
virtual void func() {
cout << "func函数调用" << endl;
}
};
void test01() {
Base *base = new Son;
base->func();
delete base;
}
int main() {
test01();
制作饮品案例:
#include<iostream>
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) {
abs->makeDrink();
delete abs;
}
void test01() {
doWork(new Coffee);
doWork(new Tea);
}
int main() {
test01();
system("pause");
return 0;
}
虚析构和纯虚析构
多态使用时,如果子类中有属性开辟到堆区,那么父类在释放时无法调用到子类的析构代码
解决方式:将父类中的析构函数改为虚析构或者纯虚析构
虚析构和纯虚析构共性:
可以解决父类指针释放子类对象
都需要有具体的函数实现
虚析构和纯虚析构区别:
如果是纯虚析构,该类属性抽象类,无法实例化对象
虚析构和纯虚析构的区别:
如果是纯虚析构,该类属于抽象类,无法实例化对象
虚析构语法:
virtual ~类名(){}
纯虚析构语法
virtual ~类名() =0;
class Animal {
public:
Animal() {
cout << "Animal构造函数" << endl;
}
virtual void speak() = 0;
virtual ~Animal() = 0;
};
Animal::~Animal() {}
class Cat :public Animal {
public:
Cat(string name) {
m_Name = new string(name);
}
virtual void speak() {
cout <<*m_Name<< "小猫在说话" << endl;
}
~Cat() {
cout << "Cat析构函数" << endl;
if (m_Name != NULL) {
delete m_Name;
m_Name = NULL;
}
}
string *m_Name;
};
void test01() {
Animal *animal = new Cat("Tom");
animal->speak();
delete animal;
}
int main() {
test01();
system("pause");
return 0;
}
类和对象案例:
#include<iostream>
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_mem != NULL) {
delete m_cpu;
m_mem = NULL;
}
if (m_vc != NULL) {
delete m_vc;
m_vc = NULL;
}
}
private:
CPU *m_cpu;
VideoCard *m_vc;
Memory *m_mem;
};
class IntelCPU :public CPU {
public:
virtual void calculate() {
cout << "Intel的CPU开始计算了!" << endl;
}
};
class LenovoMemory :public Memory {
public:
virtual void storage() {
cout << "联想的内存开始计算" << endl;
}
};
class IntelVideoCard :public VideoCard {
public:
virtual void display() {
cout << "Intel的显卡开始显示了!" << endl;
}
};
void test01() {
CPU *intelCpu = new IntelCPU;
VideoCard *intelCard = new IntelVideoCard;
Memory *intelMem = new LenovoMemory;
Computer *computer1 = new Computer(intelCpu, intelCard, intelMem);
computer1->work();
delete computer1;
}
int main() {
test01();
system("pause");
return 0;
}