定义在类内部的函数是隐式的inline函数
class A{
private:
int a;
void fun() {} // 这里的this为Sales const *this;
void fun1() const { // 这的this为 const Sales *const this;
fun();
}
};
常量对象,常量对象的的指针或指针都只能调用常量成员函数
明确指定const
istream &read(istream &is,string s)
{
is >> s;
return is;
}
ostream &print(ostream &os,const string s)
{
os << s;
return os;
}
read函数从给定流中将数据读到给定的对象中,print函数则负责将给定对象的内容打印到给定的流中.
上面的函数分别接受各自的引用作为其参数,这是因为IO类属于不能被拷贝的类型,因此只能通过引用来传递他们,而且因为读取和写入都会改变他们所以使用的都是普通引用
如果类包含了内置类型或者符合类型的成员,则只有当这些成员全都被赋予了类内的初始值时,这个类才适合于使用合成的默认构造函数
如果类包含vector或者string成员,则其拷贝,赋值,销毁的合成版本能够正常工作
.一般来说,最好在类定义开始或者结束前的位置集中声明友元.
class Person{
public:
void change() const{
age = 1; //error
name = "1221";
}
private:
mutable string name = "";
int age = 0;
};
当我们提供一个类内初始值时,必须一符号=或者花括号表示
class Person{
public:
const Person& print() const{
cout<<name<<endl;
return *this;
}
// 一个const成员函数如果以引用的形式返回*this,那么它的返回类型将是常量引用
void change(){
}
private:
mutable string name = "";
};
int main()
{
Person p;
p.print().change("xiaomi"); //error
return 0;
}
一个const成员函数如果以引用的形式返回*this,那么它的返回类型将是常量引用
class Screen;
前向声明
.他在声明之后定义之前是一个不完全类型
class Link{
Link *nesx;
}
友元之间不存在传递性,每个类负责控制自己的友元或友元函数
class Screen{
friend class Window;
private:
string name;
};
class Window{
public:
void clear(Screen& s){
s.name = "12";
}
};
class Screen;
class Window{
public:
void clear(Screen& s){
s.name = "12"; //error
}
};
class Screen{
friend void Window::clear(Screen* s);
private:
string name;
};
class Screen;
class Window{
public:
void clear(Screen& s);
};
class Screen{
friend void Window::clear(Screen& s);
private:
string name;
};
void Window::clear(Screen& s){
s.name = "12"; //error
}
class Window_mgr{
public:
using ScreenIndex = vector<Screen>::size_type;
ScreenIndex addScreen(const Screen&);
void clear(ScreenIndex);
private:
vector<Screen> sceens{Scren(24,80,' ')};
};
Window_mgr::ScreenIndex Window_mgr::addScreen(const Screen &) {
return 0;
}
因为返回类型出现在类名之前,所以事实上他是位于Window_mgr类的作用域之外的.在这种情况下,要想使用ScreenIndex作为返回类型,我们必须明确指定那个类定义了它.
typedef double Age;
class Person{
typedef double Age;
private:
Age age;
};
尽管重新定义类型名字是一种错误行为,但是编译器并不为此负责.一些编译器将顺利通过这样的代码
全局作用域: ::height
class Person{
public:
Person(int& x1,int &x2):a(x1),b(2){}
private:
int & a;
const int b;
};
建议:构造函数初始值顺序与成员声明的顺序保持一致.而且应该尽量避免使用一个成员去初始化另外一个成员.
Sales_data(std::istream &is=std::cin){ is>>*this;}
委托构造函数
.一个委托构造函数使用它所属类的其他构造函数执行它自己的初始化过程,或者说他把自己的一些职责委托给了其他函数.Sales_data obj(); //error,声明了一个函数而非对象
Sales_data obj; //正确,ogj是一个使用默认构造函数的对象
class Person{
public:
Person(const string & na):name(na),age(22){} //参数为常量引用
Person(){}
private:
string name;
int age;
};
void test(Person p )
{}
int main()
{
string s = "小米";
test(s); //编译器用给定的string自动创建了一个Sales_data对象
return 0;
}
test("小米");
这种调用时错误的.
注意:"小米"这个不是string类型这个是标注C风格字符串
使用explict关键字,在类外定义时不应重复,只能用在类的内部
.class Person{
public:
explicit Person(const string & na):name(na),age(22){} //参数为常量引用
Person(){}
private:
string name;
int age;
};
int main()
{
string name = "小米";
Person p(name);
Person p = name; //error
return 0;
}
class Person{
public:
explicit Person(const string & na):name(na),age(22){
cout<<"___________";
} //参数为常量引用
Person(){}
private:
string name;
int age;
};
void test(Person p)
{}
int main()
{
string name = "小米";
test(static_cast<Person>(name));
return 0;
}
聚合类使得用户可以直接访问其成员,其特点:
初始值的顺序必须与声明一致.
struct Data{
int ival;
string s;
}
将成员声明为const就是承诺不会修改该函数所属对象
.要想确保对象只定义一次,最好的办法是把数据成员的定义与其他内联函数的定义放在同一个文件中
class Account{
private:
static constexpr int period = 30;
double daily)_tb[period];
};
即使一个常量静态数据成员在类内部被初始化,通常情况下也应该在类的外部定义一下该成员
class Person{
public:
static constexpr int age = 12;
static const string name = "122";
};
constexpr int Person::age;
void test(Person p)
{}
int main()
{
cout<<Person::age;
return 0;
}