C++基础

VS 2017 如何查看C++ 内存结构和虚函数表

打开vs 2017的开发人员命令行提示符

cl /d1 reportSingleClassLayoutXXX D:/main.cpp

 

c++ 构造函数可以是虚函数吗?可以是纯虚函数吗? 为什么?

不可以。
因为虚函数依赖于虚函数表,该表是在构造函数中初始化的。
如果构造可以是虚函数,那么调用构造时就需要查找虚函数表,而此时虚函数表还没初始化。
所以构造函数不可以是虚函数。

c++ 析构函数可以是虚函数吗?可以是纯虚函数吗? 为什么?

 

析构函数可以是虚函数,而且对于多态使用场景,其基类的析构必须要为虚函数,否则会导致子类析构函数不被调用。
析构函数也可以是纯虚函数,但是一般没有这样使用的场景。

如何在main 前执行一个函数?

// 使用函数返回值给 全局变量 赋值 
int f()
{
    std::cout << "f" << std::endl;
    return 0;
}
int _ = f();

// 声明类对象 为全局变量
class D
{
public:
    D() { std::cout << "D" << std::endl; }
};
D d;

int main()
{
    std::cout << "main" << std::endl;

    return 0;
}

可以在C++的成员函数里调用delete this 吗?

可以,只要能够足够“安全”.
如何定义“安全”?
1,必须保证该对象是new出来的,不能是new[]出来的,不能是栈上局部变量,不能是全局变量,不能是别的对象的成员变量
2,必须保证调用完delete this 后,不再操作此对象

class D
{
public:
    D() { std::cout << "D" << std::endl; }
    ~D() { std::cout << "~D" << std::endl; }

    void print() 
    {
        std::cout << "print" << std::endl; 
        delete this;
    }
};

int main()
{
    D* d  = new D;
    d->print();

    return 0;
}

 

C++ 空类自带了哪些成员函数? 为什么拷贝赋值操作符重载函数、移动赋值操作符重载函数的返回值是引用? 如何理解移动?

/**
    C++ 空类自带了哪些成员函数?
    1,空参构造函数
    2,析构函数
    3,拷贝构造函数
    4,拷贝赋值操作符重载函数
    5,移动构造函数
    6,移动赋值操作符重载函数

    为什么拷贝赋值操作符重载函数、移动赋值操作符重载函数的返回值是引用?
    因为使用引用就可以不创建临时对象

    如何理解移动?
    为了避免拷贝,移动构造函数和移动赋值操作符重载函数的参数都是一个右值引用,即一个将亡的值,在亡之前将自己的数据移交给新的对象
*/
class D
{
public:
    D() { std::cout << "default construct" << std::endl; }
    ~D() { std::cout << "deconstruct" << std::endl; }
    D(const D& d) { std::cout << "copy construct" << std::endl; }
    D& operator=(const D& d) { std::cout << "copy assign" << std::endl; a = d.a; return *this; }
    D(D&& d) { std::cout << "move construct" << std::endl; a = d.a; }
    D& operator=(D&& d) { std::cout << "move assign" << std::endl; return *this; }

    int a;

    D getD()
    {
        D d;
        d.a = 100;
        return d;
    }
};

int main()
{
    D d;            // default construct  
    d.a = 1;

    D d2;            // default construct 
    D d3;            // default construct 
    d3 = d2 = d;    // 2 times copy assign
    std::cout << "d3.a d2.a " << d3.a << " " << d2.a << std::endl;

    D d4 = d;        // copy construct  
    D d5(d);        // copy construct  

    std::cout << "---" << std::endl;
    D d6;                // default construct 
    D d7 = d6.getD();    // move construct 
    std::cout << "d7.a " << d7.a << std::endl;

    d7 = d6.getD();        // move assign 
    std::cout << "d7.a " << d7.a << std::endl;

    std::cout << "---" << std::endl;

    return 0;
}

/**
copy assign
copy assign
d3.a d2.a 1 1
copy construct
copy construct
---
default construct
default construct
move construct
deconstruct
d7.a 100
default construct
move construct
deconstruct
copy assign
deconstruct
d7.a 100
---
deconstruct
deconstruct
deconstruct
deconstruct
deconstruct
deconstruct
deconstruct
*/

 

c++多继承的构造顺序和析构顺序?多继承需要注意的地方?

/**
c++多继承的构造顺序和析构顺序?
    跟单继承顺序一致,先构造父类,再构造子类;先析构子类,再析构父类。
多继承需要注意的地方?
    1. 对于菱形继承时,会产生命名冲突和数据冗余。可以通过虚继承来解决。虚继承是在分岔口加上virtual。
    2. 虚继承的原理: 
        2.1 首先,虚继承跟虚函数是两个概念
        2.2 虚继承的原理是,通过继承时使用virtual将基类共享
            基类中的数据将会放在最下层子类中,中间类通过虚基表去访问基类数据
            具体的过程见下面内存图
*/
class DD
{
public:
    DD() { std::cout << "DD" << std::endl; }
    ~DD() { std::cout << "~DD" << std::endl; }
    int dd;
};
class D1:virtual public DD
{
public:
    D1() { std::cout << "D1" << std::endl; }
    ~D1() { std::cout << "~D1" << std::endl; }
    int d1;
};
class D2 :virtual public DD
{
public:
    D2() { std::cout << "D2" << std::endl; }
    ~D2() { std::cout << "~D2" << std::endl; }
    int d2;
};

class S :public D1, public D2
{
public:
    S() { std::cout << "S" << std::endl; }
    ~S() { std::cout << "~S" << std::endl; }
    int s;
};
int main()
{
    S s;

    return 0;
}
/**
class S size(24):
        +---
 0      | +--- (base class D1)
 0      | | {vbptr}
 4      | | d1
        | +---
 8      | +--- (base class D2)
 8      | | {vbptr}
12      | | d2
        | +---
16      | s
        +---
        +--- (virtual base DD)
20      | dd
        +---

S::$vbtable@D1@:
 0      | 0
 1      | 20 (Sd(D1+0)DD)

S::$vbtable@D2@:
 0      | 0
 1      | 12 (Sd(D2+0)DD)
*/

LIB和DLL的区别?

LIB包含被DLL导出的函数名称和位置,DLL包含实际的函数和数据

很多人认为lib为静态库,dll为动态库,这理解并不错,但不全面。lib其实分两种的
第一种, lib是完整的静态库,里面有函数代码本身,在编译时直接将代码加入程序当中,应用程序直接使用
第二种,lib是动态库的导出声明,只包含头部信息。里面只有函数所在的DLL文件和文件中函数位置的入口,代码由运行时加载在进程空间中的DLL提供,这一点有点类似于.h在程序的作用,主要是索引作用

接口和抽象类

抽象类是对类的抽象,类是对类的抽象

而接口是对行为的抽象

 

C++里面没有专门的接口概念,而是由抽象类完成的

 

接口类和抽象类的区别在于:接口类由全部纯虚函数组成,无成员变量

 

例子1:

孙悟空  抽象 出猴  (猴是抽象类) 

猪八戒  抽象 出猪   (猪是抽象类)

孙悟空跟猪八戒都会变东西  抽象出  “变东西” 的行为  (变东西---接口类中的一个方法)

 

例子2:

飞机、火箭 抽象出 飞行器 (飞行器是抽象类)

超人 抽象出  人(人是抽象类)

它们都会飞 抽象出 “飞”的行为 (“飞” --- 接口类中的一个方法)

不同类的事物都会飞,飞就很适合作为一个接口了

 

例子3:

真实应用场景

Qt插件式开发时每个插件都涉及到和别的插件进行数据交互,而数据交互说白了就是上行和下行

插件1 抽象出 插件接口

插件2 抽象出 插件接口

我们可以单独定义一个接口(getData() updateData() ),用于数据交互。

这个例子与上面两个的不同之处在于---它是同种事物的行为。其实不用接口,仅使用抽象类也可以实现。但为了接口更加通用,单独创建了一个接口。从这里也可以看出,抽象类的设计思路是自底而上的。接口的设计是自上而下的(即接口的设计可以不用关心子类会是什么)。

 

 

 

 

 

 

 

 

 

 

接口中可以含有静态函数吗

可以

C++多线程同时操作一组图片

#include <iostream>
#include <mutex>
#include <condition_variable>
#include <thread>

std::mutex mutex;
int idx = 0;

void addOne()
{
    while (1)
    {
        std::unique_lock<std::mutex> unique_lock(mutex);
        if (idx < 1000)
        {
            std::cout << "tid and i " << std::this_thread::get_id() << " "<< idx << std::endl;
            idx++;
        }
        else
        {
            break;
        }
    }
}

int main()
{
    std::thread t1(addOne);
    std::thread t2(addOne);
    std::thread t3(addOne);
    
    t1.join();
    t2.join();
    t3.join();
    std::cout << "after i "<<idx << std::endl;
}

 

T型路口 出入

编程题

一个T字形的道路,道路宽度只够一辆车通过,其中一端是封闭的,另外两端开放。从其中一个开放端驶入一队汽车,例如各辆车编号分别为abcdefg。汽车可以选择直接从另一个开放端驶出,也可以选择进入封闭的道路等候。例如abcdefg均直接驶出,则驶出顺序为abcdefg。而如果abc直接驶出,de进入道路等候,f直接驶出,之后ed驶出,最后g直接驶出,那么驶出序列就为abcfedg。问:给出要求的驶入序列和驶出序列,推断中间过程,以及判断能否从驶入序列按照T字道路规则得到驶出序列

 C++基础

请使用C++或golang或nodejs或其他你熟悉的编程语言处理。

void parseProcess(const std::string &input, const std::string &output);

Sample1 Input:

parseProcess(“abcdefg”, “abcfedg”);

Sample1 Output:

Out

Out

Out

Hold

Hold

Out

Out from hold

Out from hold

Out

Sample2 Input:

parseProcess(“abcdefg”, “gfedcab”);

Sample2 Output:

Fail

 

C++基础

#include <iostream>
#include <string>

#include <queue>
#include <stack>
#include <list>

void process(const std::string& in, const std::string& out)
{
    std::vector<std::string> vRes;

    // 构建char 队列、char 栈
    std::queue<char> inQueue;
    std::stack<char> inStack;
    for (int i = 0; i < in.size(); i++)
        inQueue.push(in[i]);

    // 构建out list 
    std::list<char> outList;
    for (int i = 0; i < out.size(); i++)
        outList.push_back(out[i]);

    while (!inQueue.empty() || !inStack.empty())
    {
        char outing_char = outList.front();
        if (!inQueue.empty() && inQueue.front() == outing_char)
        {
            vRes.push_back("Out");
            inQueue.pop();
            outList.pop_front();
        }
        else if (!inStack.empty() && inStack.top() == outing_char)
        {
            vRes.push_back("Out from hold");
            inStack.pop();
            outList.pop_front();
        }
        else
        {
            bool valid = false;
            while (!inQueue.empty())
            {
                if (inQueue.front() == outing_char)
                {
                    valid = true;
                    break;
                }
                else
                {
                    vRes.push_back("Hold");
                    inStack.push(inQueue.front());
                    inQueue.pop();
                }
            }
            if (!valid)
            {
                std::cout << "false" << std::endl;
                return;
            }
        }
    }

    // 推断成功 打印结果
    for (auto& step : vRes)
        std::cout << step << std::endl;
}

int main()
{
    while (1)
    {
        std::string in;
        std::string out;

        std::cin >> in >> out;
        process(in, out);
    }

    return 0;
}

View Code

 

 

 

 

 

 

 

 

 

 

 

原文链接: https://www.cnblogs.com/zach0812/p/17021827.html

欢迎关注

微信关注下方公众号,第一时间获取干货硬货;公众号内回复【pdf】免费获取数百本计算机经典书籍

    C++基础

原创文章受到原创版权保护。转载请注明出处:https://www.ccppcoding.com/archives/309321

非原创文章文中已经注明原地址,如有侵权,联系删除

关注公众号【高性能架构探索】,第一时间获取最新文章

转载文章受原作者版权保护。转载请注明原作者出处!

(0)
上一篇 2023年2月16日 上午10:59
下一篇 2023年2月16日 上午10:59

相关推荐