类的创建、赋值、权限
#include<iostream>
#include<string>
using namespace std;
class stu {
public:
//属性 成员属性 成员变量
string sName;
int sId;
//行为 成员函数 成员方法
void set_sName(string name) {
sName = name;
}
void set_sId(int id) {
sId = id;
}
void showprint() {
cout << "name:" << sName << "\tid:" << sId << endl;
}
};
class tea {
//属性
public:
string tName;
protected:
int tId;
private:
int tWage;
//方法
public:
void set_tea(string name, int id, int wage) {
this->tName = name;
this->tId = id;
this->tWage = wage;
}
void showprint() {
cout << "name:" << tName << "\tid:" << tId << "\t\twage:" << tWage << endl;
}
};
struct test1 {
int struct_test = 10;//struct 默认权限为公共
};
class test2 {
int class_test = 10;//class 默认权限为私有
};
void main() {
stu tony;
//public类可以这样赋值
//tony.sName = "tony";
//tony.sId = 123;
tony.set_sName("tony");
tony.set_sId(123);
tony.showprint();
tea mary;
mary.set_tea("mary",101,1000);
mary.showprint();
test1 a;
a.struct_test = 0;//可访问
test2 b;
//b.struct_test = 0;//不可访问
}
类和对象:初始化和清理
如果不提供构造函数和析构函数,编译器会提供空实现的构造函数和析构函数。
class Person {
public://构造函数和析构函数默认是私有的,所以要加public
Person(){//程序在调用对象时候会自动调用构造
cout << "我是Person的构造函数" << endl;
}
~Person() {//程序在对象销毁前会自动调用析构
cout << "我是Person的析构函数" << endl;
}
};
void test(){
Person p;
}
void main(){
test();
system("pause");
Person person;
system("pause");
}
构造函数的分类及调用
注意1:调用无参构造函数不能加括号,如果加了编译器认为这是一个函数声明(返回类型 函数名(),Person p()——错误;)
注意2:不能利用拷贝构造函数初始化匿名对象编译器认为是对象声明
#include<iostream>
using namespace std;
class Person {
public:
int age;
int score;
//普通构造
Person() {//无参构造
cout << "无参构造函数!" << endl;
this->age = 0;
this->score = 0;
}
Person(int age, int score) {//有参构造
cout << "有参构造函数!" << endl;
this->age = age;
this->score = score;
}
//拷贝构造
Person(const Person &p) {
cout << "拷贝构造函数!" << endl;
this->age = p.age;
this->score = p.score;
}
void Show() {
cout << "age:" << age << "\tscore:" << score << endl;
}
//~Person() {
// cout << "析构函数!" << endl;
//}
};
//调用有参的构造函数
void test() {
//括号法,常用
cout << "*****括号法,常用*****" << endl;
Person p11;
p11.Show();
Person p12(20,80);
p12.Show();
Person p13(p12);
p13.Show();
//注意1:调用无参构造函数不能加括号,如果加了编译器认为这是一个函数声明——返回类型 函数名(),Person p()——错误;
//显式法
cout << endl << "*****显式法*****" << endl;
Person p21 = Person();
p21.Show();
Person p22 = Person(20,80);
p22.Show();
Person p23 = Person(p22);
p23.Show();
//Person(10)单独写就是匿名对象 当前行结束之后,马上析构
//隐式转换法
cout << endl << "*****隐式转换法*****" << endl;
Person p31 = { };//元素为空或者有多个元素时要用{ },只有一个元素时可以不用{ }直接写元素
p31.Show();
Person p32 = { 10, 80 };
p32.Show();
Person p33 = p32;
p33.Show();
//注意2:不能利用 拷贝构造函数 初始化匿名对象 编译器认为是对象声明
//Person p5(p4);
}
void main() {
test();
}
拷贝构造函数的调用时机
#include<iostream>
using namespace std;
class Person {
public:
Person() {
cout << "无参构造函数!" << endl;
this->age = 0;
}
Person(int age) {
cout << "有参构造函数!" << endl;
this->age = age;
}
Person(const Person& p) {
cout << "拷贝构造函数!" << endl;
this->age = p.age;
}
//析构函数在释放内存之前调用
~Person() {
cout << "析构函数!" << endl;
}
public:
int age;
};
//1. 使用一个已经创建完毕的对象来初始化一个新对象
void test_a() {
cout << "*****1.使用一个已经创建完毕的对象来初始化一个新对象" << endl;
Person man(100); //p对象已经创建完毕
Person newman(man); //调用拷贝构造函数
Person newman2 = man; //拷贝构造
//Person newman3;
//newman3 = man; //不是调用拷贝构造函数,赋值操作
}
//2. 值传递的方式给函数参数传值
//相当于Person p1 = p;
void doWork(Person p1) {}
void test_b() {
cout << endl << "*****2.值传递的方式给函数参数传值" << endl;
Person p; //无参构造函数
doWork(p);
}
//3. 以值方式返回局部对象
Person doWork2(){
Person p1;
cout << (int*)&p1 << endl;
return p1;
}
void test_c(){
cout << endl << "*****3.以值方式返回局部对象" << endl;
Person p = doWork2();
cout << (int*)&p << endl;
}
void main() {
test_a();
test_b;
test_c();
}
构造函数调用规则
#include<iostream>
using namespace std;
class Person {
public:
//无参(默认)构造函数
Person() {
cout << "无参构造函数!" << endl;
}
//有参构造函数
Person(int a) {
age = a;
cout << "有参构造函数!" << endl;
}
//拷贝构造函数
Person(const Person& p) {
age = p.age;
cout << "拷贝构造函数!" << endl;
}
//析构函数
~Person() {
cout << "析构函数!" << endl;
}
public:
int age;
};
void test_a()
{
Person p1(18);
//如果不写拷贝构造,编译器会自动添加拷贝构造,并且做浅拷贝操作
Person p2(p1);
cout << "p2的年龄为: " << p2.age << endl;
}
void test_b()
{
//如果用户提供有参构造,编译器不会提供默认构造,会提供拷贝构造
Person p1; //此时如果用户自己没有提供默认构造,会出错
Person p2(10); //用户提供的有参
Person p3(p2); //此时如果用户没有提供拷贝构造,编译器会提供
//如果用户提供拷贝构造,编译器不会提供其他构造函数
Person p4; //此时如果用户自己没有提供默认构造,会出错
Person p5(10); //此时如果用户自己没有提供有参,会出错
Person p6(p5); //用户自己提供拷贝构造
}
void main() {
test_a();
test_b();
}
深拷贝与浅拷贝
对象中成员含指针时,建议用深拷贝
#include<iostream>
using namespace std;
class Person {
public:
int age;
int *height;
Person() {
cout << "无参构造" << endl;
}
Person(int age, int height) {
cout << "有参构造" << endl;
this->age = age;
this->height = new int(height);//new是在堆区重新开辟一个空间,并返回的是该数据类型的指针
}
Person(const Person &p) {
cout << "拷贝构造" << endl;
this->age = p.age;
//浅拷贝,对于指针,直接复制指针,没有复制数据(两个对象中的height指针存放的地址相同,指向同一个内存空间)
//this->height = p.height;//用浅拷贝的时候,在两个对象的指针都释放的时候会报错
//深拷贝,对于指针,先在堆区域复制一个原对象指针指向的数据,再将新对象的指针指向该数据(两个对象中的height指针存放的地址不同,但两个地址的数据相同)
this->height = new int(*p.height);//用深拷贝时,对象含指针释放的时候也不会报错
}
~Person() {
cout << "析构函数!" << endl;//析构函数将堆区域的变量释放
if (height != NULL)
{
delete height;
height = NULL;//置空,防止野指针出现
}
}
};
void test() {
Person person(24, 180);
cout << "person\t\tage:" << person.age << "\thegiht" << *person.height << endl;
Person new_person(person);
cout << "new_person\tage:" << person.age << "\thegiht" << *person.height << endl;
}
void main() {
test();
}
初始对象
#include<iostream>
using namespace std;
class Person {
public:
int age;
int height;
int score;
Person(int a,int b,int c) :age(a), height(b), score(c) {//方法二初始化列表
}
void showprint() {
cout << "age:" << age << "\t\theight:" << height << "\tscore:" << score << endl;
}
};
void main() {
Person person(20,180,85);
person.showprint();
}
对象成员
#include<iostream>
#include<string>
using namespace std;
class Phone {
public:
string pname;
int price;
Phone() {}
Phone(string a, int b) :pname(a), price(b) {
cout << "phone构造函数" << endl;
}
};
class Person {
public:
string name;
Phone myphone;
Person(string a, string b, int c) :name(a), myphone(b, c) {//这里myphone(b, c)是一个隐式转换法,等价Phone myphone={b,c}
cout << "person构造函数" << endl;
}
};
void test() {
Person person("张三", "华为", 3200);
cout << "name:" << person.name << "\t\tphone:" << person.myphone.pname << "\t\tprice:" << person.myphone.price << endl;
}
void main() {
test();
}
静态成员,静态方法
#include<iostream>
#include<string>
using namespace std;
class Person {
public:
static int static_a;
int nostatic;
static void fuc_a() {
cout << "静态方法fuc_a(puplic)" << endl;
//nostatic = 100;//静态函数只能访问静态成员,非静态成员的静态函数不能访问
}
private:
static int static_b;
static void fuc_b() {
cout << "静态方法fuc_b(private)" << endl;
}
};
int Person::static_a = 0;
int Person::static_b = 0;
void test() {
//静态成员变量和静态成员方法两种访问方式
//1、通过对象
Person person;
person.static_a = 100;
//person.static_b = 100;//私有的静态成员不可访问
cout << "static_a = " << person.static_a << endl;
person.fuc_a();
//2、通过类名
cout << "static_a = " << Person::static_a << endl;
Person::fuc_a();
//Person::fuc_b();//私有的静态方法不可访问
}
void main() {
test();
}
类和对象的大小
#include<iostream>
using namespace std;
class Person_a {};//1B
class Person_b {//4B
int a;//非静态成员变量
};
class Person_c {//4B
int a;//非静态成员变量
static int static_c;//静态成员变量
};
int Person_c::static_c = 0;
class Person_d {//4B
int a;//非静态成员变量
static int static_d;//静态成员变量
void func_() {}
};
void test() {
//编译器会给空对象分配一个字节空间,为了区分空对象占内存的位置
cout << "空类占字节数:" << sizeof(Person_a) << endl;
//非静态成员变量 属于类的对象上
cout << "(只含非静态成员变量)类占字节数:" << sizeof(Person_b) << endl;
//静态成员变量 不属于类的对象上
cout << "(非静态成员变量+静态成员变量)类占字节数:" << sizeof(Person_c) << endl;
//成员函数 不属于类的对象上
cout << "(非静态成员变量+静态成员变量+函数)类占字节数:" << sizeof(Person_d) << endl;
}
void main() {
test();
}
this指针
C++中空指针也是可以调用成员函数的,但是也要注意有没有用到this指针
const修饰函数和对象
#include<iostream>
using namespace std;
class Person {
public:
public:
int m_A;
mutable int m_B; //可修改 可变的
Person() {
m_A = 0;
m_B = 0;
}
//this指针的本质是一个指针常量,指针的指向不可修改
//如果想让指针指向的值也不可以修改,需要声明常函数
void ShowPerson() const {
//const Type* const pointer;
//this = NULL; //不能修改指针的指向 Person* const this;
//this->mA = 100; //但是this指针指向的对象的数据是可以修改的
//const修饰成员函数,表示指针指向的内存空间的数据不能修改,除了mutable修饰的变量
this->m_B = 100;
cout << "常函数" << endl;
}
void MyFunc() {
//mA = 10000;
cout << "普通函数"<< endl;
}
//const修饰对象 常对象
};
void test() {
const Person person; //常量对象
cout << person.m_A << endl;
//person.mA = 100; //常对象不能修改成员变量的值,但是可以访问
person.m_B = 100; //但是常对象可以修改mutable修饰成员变量
person.ShowPerson();//常对象只能调用常函数
//常对象访问成员函数
//person.MyFunc(); //常对象不能调用普通函数
Person person11;
}
void main() {
test();
}