class 子类名:继承方式 父类名
继承方式一共有三种:
// 继承中的对象模型
class Base
{
public:
int m_A;
protected:
int m_B;
private:
int m_C;
};
class Son : public Base
{
public:
int m_D;
};
void test01()
{
// 在父类中所有非静态的成员属性都会被子类继承下去
// 父类中私有成员属性 是被编译器隐藏了,因此是访问不到。但是确实被继承下去了
cout << "size of Son= " << sizeof(Son) << endl;
}
int main()
{
test01();
system("pause");
return 0;
}
s.m_A
s.Base::m_A
- 若两个函数参数相同,但是基类函数不是虚函数,则会被隐藏。和重写的区别在于基类函数是否是虚函数。
- 若两个函数参数不同,无论基类函数是不是虚函数,都会被隐藏,两个函数在同一个类中。和重载的区别在于两个函数不在同一个类中。
// 继承中同名成员处理
class Base
{
public:
Base()
{
m_A = 100;
}
void func()
{
cout << "Base-func()调用" << endl;
}
void func(int a)
{
cout << "Son-func(int a)调用" << endl;
}
int m_A;
};
class Son : public Base
{
public:
Son()
{
m_A = 200;
}
void func()
{
cout << "Son-func()调用" << endl;
}
int m_A;
};
// 1. 同名成员属性处理
void test01()
{
Son s;
cout << "Son 下 s.m_A= " << s.m_A << endl;
// 如果通过子类对象,访问到父类中同名成员,需要加作用域
cout << "Base 下 s.m_A=" << s.Base::m_A << endl;
}
// 2. 同名成员函数处理
void test02()
{
Son s;
s.func(); // 直接调用是子类中的同名成员
s.Base::func();
// 如果子类中出现和父类同名的成员函数,子类的同名成员会隐藏掉父类中所有同名成员函数
// 如果想访问到父类中被隐藏的同名成员函数,需要加作用域
// s.func(100);
s.Base::func(100);
}
int main()
{
test01();
test02();
system("pause");
return 0;
}
静态成员变量的特点:
静态成员函数的特点:
静态成员和非静态成员出现同名,处理方式一致:(只不过有两种访问方式:对象 和 类名)
s.m_A
Son::m_A
s.Base::m_A
Son::Base::m_A
// 继承中同名静态成员处理
class Base
{
public:
static int m_A;
static void func()
{
cout << "Base-static void func()" << endl;
}
static void func(int a)
{
cout << "Base-static void func(int a)" << endl;
}
};
int Base::m_A = 100;
class Son : public Base
{
public:
static int m_A;
static void func()
{
cout << "Son-static void func()" << endl;
}
};
int Son::m_A = 200;
// 1. 同名静态成员属性
void test01()
{
cout << "通过对象访问: " << endl;
// 1、通过对象访问数据
Son s;
cout << "Son 下 m_A= " << s.m_A << endl;
cout << "Base 下 m_A=" << s.Base::m_A << endl;
// 2、通过类名访问
cout << "通过类名访问: " << endl;
cout << "Son 下 m_A= " << Son::m_A << endl;
// 第一个::代表通过类名方式来访问,第二个::代表访问父类作用域下
cout << "Base 下 m_A=" << Son::Base::m_A << endl;
}
// 2. 同名静态成员函数处理
void test02()
{
cout << "通过对象访问: " << endl;
// 通过对象访问
Son s;
s.func();
s.Base::func();
// 通过类名访问
cout << "通过类名访问: " << endl;
Son::func();
Son::Base::func(); //
// 当子类与父类拥有同名的成员函数,子类会隐藏掉父类中所有同名成员函数,加作用域可以访问到父类中同名函数。
Son::Base::func(100);
}
int main()
{
test01();
test02();
system("pause");
return 0;
}
class 子类:继承方式 父类1,继承方式 父类2...
s.Base1::m_A
s.Base2::m_A
// 多继承语法
class Base1
{
public:
Base1()
{
m_A = 100;
}
int m_A;
};
class Base2
{
public:
Base2()
{
m_A = 200;
}
int m_A;
};
// 子类 需要继承Base1和Base2
// 语法: class 子类:继承方式 父类1,继承方式 父类2...
class Son : public Base1, public Base2
{
public:
Son()
{
m_C = 300;
m_D = 400;
}
int m_C, m_D;
};
void test01()
{
Son s;
sizeof(s);
cout << "size of Son= " << sizeof(Son) << endl; // 16
// 当父类中出现同名的成员
cout << "Base1::m_A= " << s.Base1::m_A << endl;
cout << "Base2::m_A= " << s.Base2::m_A << endl;
}
int main()
{
test01();
// test02();
system("pause");
return 0;
}
菱形继承概念: 两个派生类继承同一个基类,又有某个类同时继承着两个派生类。
解决方式(利用虚继承):
virtual
变为虚继承 class Sheep : virtual public Animal {};
// 动物类
class Animal
{
public:
int m_Age;
};
// Animal称为 虚基类(最大的类)
class Sheep : virtual public Animal
{
};
// 驼类
class Tuo : virtual public Animal
{
};
// 羊驼类
class SheepTuo : public Sheep, public Tuo
{
};
void test01()
{
SheepTuo st;
st.Sheep::m_Age = 18;
st.Tuo::m_Age = 28;
// 当菱形继承,两个父类拥有相同数据,需要加以作用域区分
cout << "st.Sheep::m_Age= " << st.Sheep::m_Age << endl;
cout << "st.Tuo::m_Age= " << st.Tuo::m_Age << endl;
cout << "st.m_Age = " << st.m_Age << endl; // 28
// 利用虚继承可以直接访问,不会有二义性
}
int main()
{
test01();
system("pause");
return 0;
}
多态分为两类:
静态多态和动态多态区别:
多态满足条件:
多态使用条件:
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;
}
};
// 父类的指针或引用 指向子类对象
void doSpeak(Animal &animal) // Animal &animal =cat;
{ // 子类可以转父类,父类不能转子类
animal.speak();
}
void test01()
{
Cat cat;
doSpeak(cat);
Dog dog;
doSpeak(dog);
}
int main()
{
test01();
system("pause");
return 0;
}
virtual 返回值类型 函数名 (参数列表)=0;
纯虚函数特点:
抽象类特点:
// 纯虚函数和抽象类
class Base
{
public:
// 1、无法实例化对象
// 2、抽象类的子类必须要重写父类中的纯虚函数,否则也属于抽象类
virtual void func() = 0; // 纯虚函数
};
class Son : public Base
{
public:
virtual void func()
{
cout << "func函数调用" << endl;
};
};
void test01()
{
Base *base = new Son;
base->func();
}
int main()
{
test01();
system("pause");
return 0;
}
最好有继承关系就写虚析构!
)虚析构和纯虚析构共性:(都需要函数实现)
虚析构和纯虚析构区别:
virtual ~类名(){};
virtual ~类名()=0;
如果类包含纯虚析构函数,则必须为纯虚析构函数提供函数体
// 虚析构和纯虚析构
class Animal
{
public:
Animal()
{
cout << "Animal的构造函数调用" << endl;
}
// 利用虚析构可以解决,父类指针释放子类对象时不干净的问题
// virtual ~Animal()
// {
// cout << "Animal的虚析构函数调用" << endl;
// }
// 纯虚析构 需要声明也需要实现
// 有了纯虚析构之后,这个类也属于抽象类,无法实例化对象
virtual ~Animal() = 0;
// 纯虚函数
virtual void speak() = 0;
};
// 只能在类外实现纯虚析构
Animal::~Animal() //添加这段代码就能正常运行
{
cout << "Animal的纯虚析构函数调用" << endl;
}
class Cat : public Animal
{
public:
Cat(string name)
{
cout << "Cat的构造函数调用" << endl;
m_Name = new string(name);
}
~Cat()
{
if (m_Name != NULL)
{
cout << "Cat的析构函数调用" << endl;
delete m_Name;
m_Name = NULL;
}
}
virtual void speak()
{
cout << *m_Name << "小猫在说话" << endl;
}
string *m_Name;
};
void test01()
{
Animal *animal = new Cat("Tom");
animal->speak();
// 开辟到堆区的指针,手动释放
delete animal;
}
int main()
{
test01();
system("pause");
return 0;
}
Animal的构造函数调用
Cat的构造函数调用
Tom小猫在说话
Cat的析构函数调用
Animal的纯虚析构函数调用
(文件流)文件类型分为两种:
操作文件的三大类:
写文件步骤如下:
#include
ofstream ofs;
(名字无所谓)ofs.open("文件路径",打开方式);
ofs<<"写入的数据";
ofs.close();
文件打开方式:
打开方式 | 解释 |
---|---|
ios::in |
为读文件而打开文件 |
ios::out |
为写文件而打开文件 |
ios::ate |
初始位置: 文件尾 |
ios::app |
追加方式写文件 |
ios::trunc |
如果文件存在先删除,再创建 |
ios::binary |
二进制方式 |
注意:文件打开方式可以配合使用,使用 |
操作符
ios::binary | ios::out
#include
// 文本文件 写文件
void test01()
{
// 1.包含头文件 fstream
// 2.创建流对象
ofstream ofs;
// 3.指定打开方式
// 没有指定路径和当前.cpp的目录一样
// 路径可以写成绝对路径或者相对路径,或直接写文件名
ofs.open("test1.txt", ios::out);
// 4.写内容
ofs << "姓名:张三" << endl;
ofs << "性别:男" << endl;
ofs << "年龄: 18" << endl;
// 5.关闭文件
ofs.close();
}
int main()
{
test01();
system("pause");
return 0;
}
读文件步骤如下:
#include
ifstream ifs;
ifs.open("文件路径",打开方式);
ifs.is_open()
ifs.close();
文件打开方式:
打开方式 | 解释 |
---|---|
ios::in |
为读文件而打开文件 |
ios::out |
为写文件而打开文件 |
ios::ate |
初始位置: 文件尾 |
ios::app |
追加方式写文件 |
ios::trunc |
如果文件存在先删除,再创建 |
ios::binary |
二进制方式 |
#include
#include
// 文本文件 读文件
void test01()
{
// 1.包含头文件
// 2.创建流对象
ifstream ifs;
// 3.打开文件并判断是否打开成功
ifs.open("test.txt", ios::in);
// 判断文件是否打开成功
if (!ifs.is_open())
{
cout << "文件打开失败了" << endl;
return;
}
// 4.读数据
// 第一种
char buf[1024] = {0};
while (ifs >> buf) // 读到头返回一个假的标志
{
cout << buf << endl;
}
// 第二种
char buf[1024] = {0};
// ifs对象内有成员函数
// ifs.getline(char *(传入首地址),sizeof()(统计字节数))
while (ifs.getline(buf, sizeof(buf)))
{ // getline()返回bool类型
cout << buf << endl;
}
// 第三种(较好)
string buf;
// 全局函数getline
while (getline(ifs, buf))
{
cout << buf << endl;
}
// 第四种 不推荐
char c; // EOF判断是否没有到达文件尾
while ((c = ifs.get()) != EOF) // EOF end of file
{ // 中文每个占多个字节,用endl就分开了
cout << c;
}
// 5.关闭文件
ifs.close();
}
int main()
{
test01();
return 0;
}
文件打开方式:
打开方式 | 解释 |
---|---|
ios::in |
为读文件而打开文件 |
ios::out |
为写文件而打开文件 |
ios::ate |
初始位置: 文件尾 |
ios::app |
追加方式写文件 |
ios::trunc |
如果文件存在先删除,再创建 |
ios::binary |
二进制方式 |
ios::binary
ofstream
调用成员函数 ofs.write()
wirte()
函数原型:ofs.write(const char* buffer, sizeof(len);
#include
// 二进制文件 写文件
class Person
{
public:
// 对文件操作,写字符串最好不要用C++的string,会出现问题
char m_Name[64]; // 姓名
int m_Age; // 年龄
};
void test01()
{
// 1.包含头文件
// 2.创建流对象
// ofs对象有构造函数,直接初始化
ofstream ofs("person.txt", ios::out | ios::binary);
// 3.打开文件
// ofs.open("person.txt", ios::out | ios::binary);
// 4.写文件
Person p = {"张三", 18};
// 强制转换,原来为Person*
ofs.write((const char *)&p, sizeof(Person));
// 5.关闭文件
ofs.close();
}
int main()
{
test01();
return 0;
}
ifstream
调用成员函数 ifs.read()
read()
函数原型:ifs.read(char *buffer,sizeof(len));
#include
class Person
{
public:
char m_Name[64]; // 姓名
int m_Age; // 年龄
};
// 二进制文件读文件
void test01()
{
// 1.包含头文件
// 2.创建流对象
ifstream ifs;
// 3.打开文件 判断文件是否打开成功
ifs.open("person.txt", ios::in | ios::binary);
if (!ifs.is_open())
{
cout << "文件打开失败" << endl;
return;
}
// 4.读文件
Person p;
ifs.read((char *)&p, sizeof(Person));
cout << "姓名为:" << p.m_Name << endl;
cout << "年龄为:" << p.m_Age << endl;
// 5.关闭文件
ifs.close();
}
int main()
{
test01();
return 0;
}