- C语言中struct 默认是公有成员,C++中class 默认是私有成员
- private:除了类内部之外都不可以使用
- public:对外暴露的,外界会具有读写操作权限
权限选择:必须要对外界提供的,放在public,其余的都放在private
class Person
{
private:
int _age;
int _sex;
char* _name; //这三个成员属性默认为私有,但可以通过函数接口去使用它们
public:
Person()
{
cout << "Person()" << endl;
}
Person(int age)
{
cout << "Person(int age)" << endl;
_age = age;
_name = NULL;
}
int Get_age() //通过函数接口可以读取年龄值
{
return _age;
}
void Set_age(int age) //通过函数接口可以改变年龄值
{
_age = age;
}
//但是这样的化_age属性与共有存在没有区别,都可以读或者改变_age的值
//所以一般在使用时,我们都会设置访问这些属性的身份,如下:
void Set_age(int age, int who)
{
if (who == 1)
{
_age = age;
}
}
~Person()
{
cout << "~Person" << endl;
delete[]_name;
}
};
初始化与赋值的区别
- 初始化:在定义的时候给值,内存划分时候给值
- 赋值:定义之后给值,内存划分完后之后给值
初始化列表
- 只有构造函数有初始化列表
- 必须初始化的成员需要放在初始化列表,eg:const成员和引用成员必须初始化,所以必须放在初始化列表,因为在编译时期将有引用的的地方都换成了引用底层的解引用
- 在本对象构造之前需要完成的动作,必须放在初始化列表
- 拷贝函数依然是构造函数,所以它也应该有初始化列表
int id;
class Person
{
private:
int _age;
const int _sex;
char* _name;
int& ID;
public:
Person():_sex(1), ID(id) //const与引用都必须在初始化列表
{
cout << "Person()" << endl;
}
Person(int age) :_sex(1), ID(id)
{
cout << "Person(int age)" << endl;
_name = NULL;
}
~Person()
{
cout << "~Person" << endl;
delete[]_name;
}
};
const常对象
- 常对象只能调用常方法,构造函数,析构函数,静态函数不影响
- 常方法中只能调用常方法,静态函数不影响
- 普通对象调用常方法是可以的,常对象不能调用普通方法
- 哪些成员方法需要写成常方法:1.如果成员方法内不需要改动成员,并且没有对外暴露成员引用或者指针,就可以直接写成常方法 2.如果成员方法内部不需要改动成员,但是会对外暴露成员引用或者指针,就写两个成员方法(const方法和非const方法),形成重载 3.如果成员方法内部需要改动成员,就写成普通函数
class Person
{
private:
int _age;
int _sex;
char* _name;
public:
Person()
{
cout << "Person()" << endl;
}
Person(int age)
{
cout << "Person(int age)" << endl;
_age = age;
_name = NULL;
}
Person(const char* name, int age, int sex)
{
_age = age;
_sex = sex;
_name = new char[strlen(name) + 1];
memset(_name, 0, strlen(name) + 1);
for (int i = 0; i < strlen(name); i++)
{
_name[i] = name[i];
}
}
int get_age()//Person* const this
{
return _age;
}
void set_age(int age)
{
_age = age;
}
~Person()
{
cout << "~Person" << endl;
delete[]_name;
}
};
int main()
{
const Person p1("xiaohua", 18, 0);//p1是一个常量
cout << p1.get_age() << endl;//调用出问题
cout << p1.set_age() << endl;//调用出问题
//为什么会出问题?
//因为参数列表不匹配,this指针不匹配
//函数的第一个参数为 Person* const this ,this指针是个常量
//指向p1的指针是Person const *p = &p1;对象是个常量
//将常量的地址给了一个非常量的指针,暴露了常量的地址
return 0;
}
解决方案如下:
int get_age()//Person* const this --->Person const * const this,
{ //解决方案是多加一个const,即让this指针指向的内容不可改变
//如何加又是一个问题?
return _age;
}
//加const之后叫常方法
int get_age()const //将const加在后边就等价于Person const * const this
{ //还有一个引申出的问题是普通的对象可以调用常方法吗?可以,将一个非常量地址给一个常量指针是可以的,相当于安全性增加
return _age;
}
int get_age()const //常方法中不能调用普通函数,因为调用普通函数传入的类型为常方法中this的类型
{
set_age(10); //this->set_age(10); 常对象是不能调用普通函数的,又会出现上述那种情况,将一个常指针给一个普通指针
return _age;
}
void set_age(int age)
{
_age = age;
}