基本类型的大小随编译器决定,下面以32位为例
类型 | 大小 (字节) |
---|---|
bool | 未定义 |
char | 1 |
short | 2 |
int | 4 |
long | 4 |
long long | 8 |
float | 4 |
double | 8 |
template<class T>
typename std::remove_reference<T>::type&& move(T&& a) noexcept
{
return static_cast<typename std::remove_reference<T>::type&&>(a);
}
template< class T > T&& forward( typename std::remove_reference<T>::type& t )
{
return static_cast<T&&>(t);
}
template< class T > T&& forward( typename std::remove_reference<T>::type&& t )
{
return static_cast<T&&>(t);
}
double Sales_data::avg_price() const {
if (unit_sold) {
return revenue/units_sold;
} else {
return 0;
}
}
防止函数隐式转换,在单参数的构造函数声明时用得较多。
类似于函数,但是其()中的参数不是真的函数参数,在编译器进行宏展开时对()里的参数进行"一对一"的替换。
类的常量和引用成员必须在初始化列表中初始化,因为这两类成员不支持赋值操作,对象通过初始化列表初始化避免调用对象的默认构造函数进行初始化,因此效率更高。
// 结构体
struct Car {
string type,
int tire_nums
}
5.类:类的基本思想是数据抽象和封装,抽象依赖于接口和动态实现的分离的编程。类是C++实现面向对象编程的三大特征:继承、封装、动态的方式之一;类具备构造函数和析构函数。
std::string isbn() const { return this->bookNo; }
返回对象本身
Sale_data& Sale_data::combie(const Sale_data& rhs) {
units_sold += rhs.units_sold;
revenus += rhs.revenus;
return *this;
}
lass B; //前向引用声明
class A//A类的定义
{
public://外部接口
void f(B b);//以B类对象b为形参的成员函数
};
class B//B类的定义
{
public://外部接口
void g(A a);//以A类对象a为形参的成员函数
};
Struct主要用于数据类型的定义,Class用于面向对象的实现,包含一组相关的数据和行为。
最主要的区别在于默认访问控制不一样:
vector
deque
list
forward_list
array
string
容器的拷贝——对象间数据分离
vector<string> v1;
{
vector<string> v2 = {"a", "b", "an"};
v1 = v2;
} // v2被释放,但是v1的数据还是存在,是之前v2元素的拷贝
class Foo {
public:
Foo();
Foo(Foo& other); // 拷贝构造函数必须使用引用,避免循环拷贝
};
class Foo {
public:
Foo();
Foo& operator=(const Foo& other); // 重载赋值运算符
};
,而且数据成员的销毁顺序和在构造函数中初始化的顺序相反。
class Foo {
public:
Foo();
~Foo(); // 析构函数
};
class Foo {
public:
Foo();
Foo(Foo& other) = delete; // 阻止拷贝
Foo& operator=(const Foo& other) = delete; // 阻止赋值
~Foo() = defalut; // 使用合成的析构函数
};
除了上述方式,类通过将其拷贝构造函数或者赋值构造函数声明为private成员可以阻止拷贝。
C++中封装通过对类的访问权限实现,类将客观事物抽象成数据成员和方法,并通过public,protected,private三种访问权限控制其他对象对类的访问和继承。
public
成员:可以被任意实体访问protected
成员:只允许被子类及本类的成员函数访问private
成员:只允许被本类的成员函数、友元类或友元函数访问上述继承方式,默认使用private继承方式。
#include <iostream>
using namespace std;
class Base {
public:
Base(){
cout<< "Base" << endl;
}
};
class DerivedA: public Base{
public:
DerivedA(){
cout<< "Derived A" << endl;
}
};
class DerivedB: public Base{
public:
DerivedB(){
cout<< "Derived B"<<endl;
}
};
class DerivedAll: public DerivedA,public DerivedB{
public:
DerivedAll(){
cout<< "Derived All"<<endl;
}
};
int main()
{
DerivedAll a;
return 0;
}
结果输出:
Base
Derived A
Base
Derived B
Derived All
子类构造函数调用时调用了两次父类的构造函数,即存在两份父类对象在内存中,为了避免上述情况,引入虚基类,即继承前加上virtual。
class DerivedA: virtual public Base{
public:
DerivedA(){
cout<< "Derived A" << endl;
}
};
class DerivedB: virtual public Base{
public:
DerivedB(){
cout<< "Derived B"<<endl;
}
};
现在运行结果如下:
Base
Derived A
Derived B
Derived All
#include <iostream>
using namespace std;
class Base {
public:
void virtual func(){
cout<< "Base"<<endl;
}
};
class DerivedA: public Base{
public:
void func(){
cout<< "Derived A"<<endl;
}
};
int main()
{
Base * pb = new DerivedA();
pb->func();
return 0;
}
上述代码打印结果是:
Derived A
如果 func不是虚函数,则pb指针对象使用的仍是基类指针对象,故调用的是基类的func函数。
每个虚继承的子类都有一个虚基类指针(占用一个指针的存储空间,4字节)和虚基类表(不占用类对象的存储空间)
当派生类重新定义虚函数时,则将派生类的虚函数的地址添加到虚函数表中。当一个基类指针指向一个派生类对象时,虚函数表指针指向派生类对象的虚函数表。当调用虚函数时,由于派生类对象重写了派生类对应的虚函数表项,基类在调用时会调用派生类的虚函数,从而产生多态。
using namespace std;
class Base {
public:
virtual ~ Base(){
cout<< "delete Base" << endl;
}
virtual void func(){
cout<< "Base func"<<endl;
}
};
class Derived: public Base{
public:
~ Derived(){
cout << "delete Derived"<< endl;
}
void func(){
cout<< "Derived func2"<<endl;
}
};
int main()
{
Base * pb = new Derived();
pb->func();
delete pb;
return 0;
}
运行结果如下:
Derived func2
delete Derived
delete Base
若Base的析构函数是普通函数,则delete pb时只会调用Base的析构函数
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。