#include <iostream>
#include <string>
using namespace std;
/*
OOP的三大特性:封装 继承 多态
封装:
将静态属性和动态行为封装成一个整体
属性和行为加以权限控制:public private protect
public:类外 类内都可访问
private:类外不可访问 类内可以访问
protect:类外不可访问 类内可以访问
struct与class的区别:struct默认权限是public class的默认权限是private
构造函数:创建对象时,为对象的成员属性赋初始值,构造函数由编译器自行调用
1.无返回值
2.函数名与类名相同
3.可以进行函数重载,可以有参数
4.每次创建调用时会自动调用构造函数,且只会调用一次
构造函数的分类:
1.按参数分类:有参构造函数 无参构造函数
2.按类型分类:普通构造函数 拷贝构造函数
构造函数的调用方式: 括号法 显示法 隐式转换法
拷贝构造函数调用时机:
1.用一个已有对象去初始化一个新的对象;
2.值传递的方式给函数参数传递值;
3.以值传递方式返回局部对象;
构造函数的调用规则:
1.默认情况下,c++编译器至少给一个类添加3个函数:默认构造函数(无参数) 默认析构函数(无参数) 默认拷贝构造函数(对属性进行值拷贝)
2.如果用户定义了有参构造函数,c++不会再提供无参数的默认构造函数,但是会提供默认拷贝构造函数;
3.如果用户定义了拷贝构造函数,c++不会再提供其他构造函数;
析构函数:销毁对象前,系统自动调用清理内存
1.无返回值
2.函数名与类名相同,且加上~
3.析构函数无参数,不可以进行函数重载
4.对象销毁前会自动调用析构函数
// 浅拷贝与深拷贝
// 浅拷贝:简单的赋值拷贝操作
// 深拷贝:在heap上重新申请空间,进行拷贝操作
// 类对象作为类成员:C++中类的成员可以是另一个类的对象,称为对象成员
class A{
};
// 创建B对象时,A和B的构造函数与析构函数谁先谁后呢?---先调用对象成员的构造函数,再调用本类的构造函数
class B{
public:
A a;
};
// 必须使用列表初始化的场景:
注意:成员是按照他们在类中出现的顺序进行初始化的,而不是按照他们在初始化列表出现的顺序初始化的
1.常量成员,因为常量只能初始化不能赋值,所以必须放在初始化列表里面
2.引用类型,引用必须在定义的时候初始化,并且不能重新赋值,所以也要写在初始化列表里面
3.没有默认构造函数的类类型,因为使用初始化列表可以不必调用默认构造函数来初始化,而是直接调用拷贝构造函数初始化。
// 静态成员:在成员变量或成员函数前加上static关键字
静态成员分为:
静态成员变量:
1.所有对象共享同一份数据
2.在编译阶段分配内存
3.类内声明,类外进行初始化
静态成语函数:
1.所有对象共享同一个函数
2.静态成员函数只能访问静态成员变量
*/
const double PI = 3.14;
class Circle{
public:
explicit Circle(int r):m_r(r) {}
virtual ~Circle(){}
double calculateZC() {
return 2 * PI * m_r;
}
private:
int m_r;
};
class Student {
public:
Student(string name, int age, int id):m_name(name) ,m_age(age), m_id(id) {}
~Student() {}
void showStudentInfo() {
cout << m_name << " " << m_age << " " << m_id << endl;
}
int m_aa;
private:
string m_name;
int m_age;
int m_id;
};
// 构造函数的分类及调用
class Person{
public:
// 无参数的构造函数
Person() {
cout << "not params\n";
}
// 有参的构造函数
Person(int age): m_age(age) {
cout << "display params age\n";
}
// 拷贝构造函数
Person(const Person& p) {
m_age = p.m_age;
cout << "copy constructor has been called\n";
}
// 析构函数
~Person(){
cout << "deconstructor function\n";
}
public:
int m_age;
};
// 1.使用一个已初始化的对象来初始化一个新对象
void test01() {
Person man(100); // man是一个已经创建好的对象
Person newman(man); // 调用拷贝构造函数
Person newman2 = man; // 调用拷贝构造函数
// Person newman3;
// newman3 = man; // 不调用拷贝构造函数,只是普通赋值操作
}
// 2.以值传递的方式给函数传递参数
void doWork(Person p) {
cout << "doWork: " << (int*)&p << endl;
}
void test02(){
Person p; // 无参构造函数
doWork(p);
}
// 3.以值传递的方式返回局部对象
Person doWork2() {
Person p1;
cout << "doWork2: " << (int*)&p1 << endl;
return p1;
}
void test03() {
Person p = doWork2();
cout << "test03: " << (int*)&p << endl;
}
// 构造函数的调用规则
void test04() {
Person p1(18);
// 如果不写拷贝构造函数,编译器会自动添加拷贝构造函数,并且做浅拷贝操作
Person p2(p1);
cout << "p2 age is: " << p2.m_age << endl;
}
// 浅拷贝与深拷贝
class Test {
public:
// 默认构造函数
Test() {
cout << "默认构造函数\n";
}
// 用户自定义构造函数
Test(int age, int height) {
m_age = age;
m_height = new int (height);
}
// 拷贝构造函数
Test(const Test& t) {
cout << "Test copy structor\n";
m_age = t.m_age;
m_height = new int (*t.m_height);
}
// 析构函数
~Test() {
cout << "Test deconstructor function\n";
if(m_height) {
delete m_height;
}
}
int m_age;
int* m_height;
};
// 如果对象的属性中有在heap上开辟的,一定要自己提供拷贝构造函数,不能使用默认的拷贝构造函数(浅拷贝)
void test05() {
Test t1(18, 172);
Test t2(t1);
cout << "t1.age=" << t1.m_age << " *t1.m_height=" << *t1.m_height << endl;
cout << "t2.age=" << t2.m_age << " *t2.m_height=" << *t2.m_height << endl;
}
// 类对象作为类成员
class Phone {
public:
Phone(string name) {
m_name = name;
cout << "Phone constructor\n";
}
~Phone() {
cout << "Phone deconstructor\n";
}
string m_name;
};
class Curry {
public:
Curry(string name, string pName): m_name(name), m_phone(pName) {
cout << "Curry constructor\n";
}
~Curry() {
cout << "Curry deconstructor\n";
}
void playGame(){
cout << m_name << " is using " << m_phone.m_name << " play games\n";
}
string m_name;
Phone m_phone; // 类中成员m_phone是Phone类的对象时,此时m_phone称为对象成员
};
void test06() {
// 构造顺序:先调用对象成员的构造函数,再调用本类的构造函数;析构对象时顺序相反
Curry cu("Curry", "xiaomi");
cu.playGame();
}
// 静态成员变量与静态成员函数
// 静态成员变量
// 1.所有对象共享同一份数据
// 2.在编译阶段分配内存
// 3.类内声明,类外初始化
// 静态成员函数
// 1.所有对象共享同一个函数
// 2.静态成员函数只能访问静态成员变量
class Hello{
public:
static int m_H; // 静态成员变量
int m_HO; // 普通成员变量
// 静态成员函数
static void func1(){
cout << "func1 is called\n";
m_H = 666; // 静态成员函数只能访问静态成员变量
// m_HO = 721; 错误,不可访问非静态成员变量
}
private:
static int m_L;
static void func2() {
cout << "func2 is called\n";
}
};
// 静态成员变量在类外初始化
int Hello::m_H = 100;
int Hello::m_L = 102;
// 静态成员变量的访问方式
void test07() {
// 1.通过对象
Hello h;
h.m_H = 134;
cout << "h.m_H =" << h.m_H << endl;
Hello h1;
h1.m_H = 999;
// 共享同一份数据
cout << "h.m_H =" << h.m_H << endl;
cout << "h1.m_H =" << h1.m_H << endl;
// 2.类名直接访问
cout << "h.m_H =" << Hello::m_H << endl;
// 静态成员函数的访问方式
// 1.通过对象
Hello h2;
h2.func1();
cout << "h2.m_H =" << h2.m_H << endl;
// 2.通过类名
Hello::func1();
// Hello::func2(); 没有访问权限
cout << "Hello::m_H =" << Hello::m_H << endl;
}
// C++中的对象模型和this指针
// 1.在c++中,类内的成员变量和成员函数分开存储
// 2.只有非静态成员变量才属于类的对象上
class Student1{
public:
Student1() {
m_id = 0;
}
// 普通成员函数也不占用对象空间,所有函数共用一个函数实例
void func() {
cout << "m_id = " << this->m_id << endl;
}
// 静态成员函数不占用对象空间
static void sfunc() {
cout << "TODO\n";
}
private:
// 非静态成语变量占用对象空间
double m_id;
// 静态成员变量不占用对象空间
static int m_tel;
};
// this指针概念:
// cpp中成员变量和成员函数是分开存储的----->每个非静态成员函数只会产生一份函数实例,即多个同类型的对象会共用一块代码
// -------->同一块非静态成员函数代码如何区分哪个对象调用自己的?
// cpp通过特殊的对象指针this解决,this指针指向被调用的成员函数所属的对象
// this指针是隐含每一个非静态成员函数内的一种指针;
// this指针用途:当形参和成员变量同名时,可以用this指针来区分;在类的非静态成员函数中返回对象本身return *this
class Teacher{
public:
Teacher(int age) {
// 1.当形参和成员变量同名时,用this指针来区分
this->age = age;
}
Teacher(const Teacher& t) {
cout << "teacher copy constructor\n";
}
Teacher& TeacherAddTeacher(Teacher t){ // 会调用拷贝构造函数
this->age += t.age;
// 2.返回对象本身
return *this;
}
int age;
};
// 空指针访问成员函数
// cpp中空指针也是可以访问成员函数的,注意有没有用到this指针,如果用到则需要加判断来保证代码的健壮性
class Player{
public:
void showClassName(){
cout << "Class Player\n";
}
void showPlayer(){
if(this == nullptr) return;
cout << mAge << endl;
}
public:
int mAge;
};
void test11() {
Player* p = nullptr;
p->showClassName(); // 空指针,可以调用成员函数
p->showPlayer(); // 但是如果成员函数中用到了this指针,就不可以了
}
// const修饰成员函数
// 常函数:
// 成员函数后加const后这个函数称为常函数
// 常函数内部不可以修改成员属性
// 成员属性声明时加关键字mutable时,在常函数内部依然可以修改
// 常对象:
// 声明对象前加const称此对象是常对象
// 常对象只能调用常函数
class Const{
public:
Const(){
m_A = 0;
m_B = 0;
}
// this指针的本质是一个指针常量,指针的指向不可以改变
// 如果希望指针指向的值也不可以修改,需要声明为常函数
void showConst() const {
// const修饰成员函数,表示指针指向的内存空间的数据不能被修改,除了mutable修饰的变量
this->m_B = 100;
}
void MyFunc() const {
// m_A = 100;
}
public:
int m_A;
mutable int m_B;
};
void test22() {
const Const cs; // 常对象cs
cout << cs.m_A << endl;
// cs.mA = 100; 常对象不能修改成员变量的值,但可以访问
cs.m_B = 1000;
cs.MyFunc(); // 常对象只能访问常成员函数
}
int main() {
// Circle c(2); 显式
// Circle c = 10; 隐式
Circle c(10);
cout << "ZC is: " << c.calculateZC() << endl;\
Student stu("zhangsan", 18, 1120001);
stu.showStudentInfo();
// stu.m_name; 类外不可以访问
// stu.m_aa; 类外可以访问
// 构造函数的分类及调用
Person p; // 调用无参构造函数
Person p1(10); // 括号法 显示法
Person p2 = 20; // 隐式转换法
Person p3 = Person(18);
Person p4 = p2; // 调用拷贝构造函数
test02();
test03();
cout << "--------test04---------\n";
test04();
cout << "--------Test---------\n";
test05();
cout << "--------test06---------\n";
test06();
cout << "--------test07---------\n";
test07();
cout << "--------test08---------\n";
cout << "sizeof(Student1) = " << sizeof(Student1) << endl;
cout << "--------test09---------\n";
Student1 s1;
s1.func();
cout << "--------test10---------\n";
Teacher t1(24);
cout << "t1.age = " << t1.age << endl;
cout << "-----split line---------\n";
Teacher t2(35);
t2.TeacherAddTeacher(t1).TeacherAddTeacher(t1).TeacherAddTeacher(t1);
cout << "t2.age = " << t2.age << endl;
cout << "--------test11---------\n";
test11();
cout << "--------test22---------\n";
test22();
return 0;
}
C++基础复习3
最后编辑于 :
©著作权归作者所有,转载或内容合作请联系作者
- 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
- 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
- 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
推荐阅读更多精彩内容
- 每年总会安排时间进行基础复习,这次关注的是c语言数据结构设计及c++设计模式。 将c语言采用了面向对象的设计方法,...
- 注意事项 对于不带.h的头文件,所有的符号都位于命名空间 std 中,使用时需要声明命名空间 std;对于带.h的...